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.
28 #define FG_COLOR grd_curcanv->cv_font_fg_color
29 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
33 static ConsoleInformation Console;
34 #define console (&Console)
36 /* console is ready to be written to */
37 static int con_initialized;
41 void CON_UpdateOffset(void);
42 /*! Frees all the memory loaded by the console */
45 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
46 255 - opaque). Use this function also for OpenGL. */
47 void CON_Alpha(unsigned char alpha);
48 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
49 Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
50 void CON_AlphaGL(SDL_Surface *s, int alpha);
51 /*! Sets a background image for the console */
53 int CON_Background(grs_bitmap *image);
54 /*! Sets font info for the console */
55 void CON_Font(grs_font *font, int fg, int bg);
56 /*! Beams a console to another screen surface. Needed if you want to make a Video restart in your program. This
57 function first changes the OutputScreen Pointer then calls CON_Resize to adjust the new size. */
58 int CON_Transfer(grs_screen* new_outputscreen, int x, int y, int w, int h);
59 /*! Modify the prompt of the console */
60 void CON_SetPrompt(char* newprompt);
61 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
62 ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
63 void CON_SetHideKey(int key);
64 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
65 void CON_Execute(char* command);
66 /*! Internal: Gets called when TAB was pressed */
67 void CON_TabCompletion(void);
68 /*! Internal: makes newline (same as printf("\n") or CON_Out("\n") ) */
69 void CON_NewLineConsole(void);
70 /*! Internal: shift command history (the one you can switch with the up/down keys) */
71 void CON_NewLineCommand(void);
72 /*! Internal: updates console after resize etc. */
73 void CON_UpdateConsole(void);
76 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
77 void DrawCommandLine();
79 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
80 void Cursor_Left(void);
81 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
82 void Cursor_Right(void);
83 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
85 void Cursor_Home(void);
86 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
87 void Cursor_End(void);
88 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
89 void Cursor_Del(void);
90 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
91 void Cursor_BSpace(void);
92 /*! Internal: Called if you type in a character (add the char to the command) */
93 void Cursor_Add(int event);
95 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
96 void Clear_Command(void);
97 /*! Internal: Called if you press Ctrl-L (deletes the History) */
98 void Clear_History(void);
100 /*! Internal: Called if you press UP key (switches through recent typed in commands */
101 void Command_Up(void);
102 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
103 void Command_Down(void);
106 /* Takes keys from the keyboard and inputs them to the console
107 If the event was not handled (i.e. WM events or unknown ctrl-shift
108 sequences) the function returns the event for further processing. */
109 int CON_Events(int event)
114 if(event & KEY_CTRLED)
117 switch(event & ~KEY_CTRLED)
136 else if(event & KEY_ALTED)
138 //the console does not handle ALT combinations!
143 //first of all, check if the console hide key was pressed
144 if(event == console->HideKey)
149 switch (event & 0xff)
155 if(event & KEY_SHIFTED)
157 console->ConsoleScrollBack = console->LineBuffer-1;
164 if(event & KEY_SHIFTED)
166 console->ConsoleScrollBack = 0;
173 console->ConsoleScrollBack += CON_LINE_SCROLL;
174 if(console->ConsoleScrollBack > console->LineBuffer-1)
175 console->ConsoleScrollBack = console->LineBuffer-1;
180 console->ConsoleScrollBack -= CON_LINE_SCROLL;
181 if(console->ConsoleScrollBack < 0)
182 console->ConsoleScrollBack = 0;
204 console->InsMode = 1-console->InsMode;
210 if(strlen(console->Command) > 0) {
211 CON_NewLineCommand();
213 // copy the input into the past commands strings
214 strcpy(console->CommandLines[0], console->Command);
216 // display the command including the prompt
217 CON_Out("%s%s", console->Prompt, console->Command);
220 CON_Execute(console->Command);
223 console->CommandScrollBack = -1;
231 if (key_to_ascii(event) == 255)
245 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
246 * specified value. Preconditions: the surface in question is RGBA.
247 * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
248 void CON_AlphaGL(SDL_Surface *s, int alpha) {
253 SDL_PixelFormat *format;
254 static char errorPrinted = 0;
257 /* debugging assertions -- these slow you down, but hey, crashing sucks */
259 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
263 /* clamp alpha value to 0...255 */
264 if(alpha < SDL_ALPHA_TRANSPARENT)
265 val = SDL_ALPHA_TRANSPARENT;
266 else if(alpha > SDL_ALPHA_OPAQUE)
267 val = SDL_ALPHA_OPAQUE;
271 /* loop over alpha channels of each pixel, setting them appropriately. */
275 switch (format->BytesPerPixel) {
277 /* 16-bit surfaces don't seem to support alpha channels. */
280 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
284 /* we can do this very quickly in 32-bit mode. 24-bit is more
285 * difficult. And since 24-bit mode is reall the same as 32-bit,
286 * so it usually ends up taking this route too. Win! Unroll loop
287 * and use pointer arithmetic for extra speed. */
288 int numpixels = h * (w << 2);
289 Uint8 *pix = (Uint8 *) (s->pixels);
290 Uint8 *last = pix + numpixels;
292 if((numpixels & 0x7) == 0)
293 for(pixel = pix + 3; pixel < last; pixel += 32)
294 *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
296 for(pixel = pix + 3; pixel < last; pixel += 4)
301 /* we have no choice but to do this slowly. <sigh> */
302 for(y = 0; y < h; ++y)
303 for(x = 0; x < w; ++x) {
305 /* Lock the surface for direct access to the pixels */
306 if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
307 PRINT_ERROR("Can't lock surface: ");
308 fprintf(stderr, "%s\n", SDL_GetError());
311 pixel = DT_GetPixel(s, x, y);
314 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
315 pixel = SDL_MapRGBA(format, r, g, b, val);
316 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
317 DT_PutPixel(s, x, y, pixel);
319 /* unlock surface again */
321 SDL_UnlockSurface(s);
329 /* Updates the console buffer */
330 void CON_UpdateConsole(void) {
334 grs_canvas *canv_save;
337 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
341 Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
343 canv_save = grd_curcanv;
344 gr_set_current_canvas(console->ConsoleSurface);
347 SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
353 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
354 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
357 /* draw the background image if there is one */
358 if(console->BackgroundImage)
359 gr_bitmap(0, 0, console->BackgroundImage);
361 /* Draw the text from the back buffers, calculate in the scrollback from the user
362 * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
363 * for the font, and then clear it when we're done.
366 if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
367 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
368 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
372 //now draw text from last but second line to top
373 for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
374 if(console->ConsoleScrollBack != 0 && loop == 0)
375 for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
377 orig_color = FG_COLOR;
378 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);
379 FG_COLOR = orig_color;
383 orig_color = FG_COLOR;
384 gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
385 FG_COLOR = orig_color;
389 gr_set_current_canvas(canv_save);
392 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
393 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
397 void CON_UpdateOffset(void) {
398 switch(console->Visible) {
400 console->RaiseOffset -= CON_OPENCLOSE_SPEED;
401 if(console->RaiseOffset <= 0) {
402 console->RaiseOffset = 0;
403 console->Visible = CON_CLOSED;
407 console->RaiseOffset += CON_OPENCLOSE_SPEED;
408 if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
409 console->RaiseOffset = console->ConsoleSurface->cv_h;
410 console->Visible = CON_OPEN;
419 /* Draws the console buffer to the screen if the console is "visible" */
420 void CON_DrawConsole(void) {
421 grs_canvas *canv_save;
424 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
425 if(console->Visible == CON_CLOSED)
428 /* Update the scrolling offset */
431 /* Update the command line since it has a blinking cursor */
435 /* before drawing, make sure the alpha channel of the console surface is set
436 * properly. (sigh) I wish we didn't have to do this every frame... */
437 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
438 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
441 canv_save = grd_curcanv;
442 gr_set_current_canvas(&console->OutputScreen->sc_canvas);
444 clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
446 gr_bitmap(0, 0, clip);
447 gr_free_sub_bitmap(clip);
450 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
451 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
454 gr_set_current_canvas(canv_save);
458 /* Initializes the console */
459 void CON_Init(grs_font *Font, grs_screen *DisplayScreen, int lines, int x, int y, int w, int h)
463 console->Visible = CON_CLOSED;
464 console->RaiseOffset = 0;
465 console->ConsoleLines = NULL;
466 console->CommandLines = NULL;
467 console->TotalConsoleLines = 0;
468 console->ConsoleScrollBack = 0;
469 console->TotalCommands = 0;
470 console->BackgroundImage = NULL;
472 console->ConsoleAlpha = SDL_ALPHA_OPAQUE;
475 console->InsMode = 1;
476 console->CursorPos = 0;
477 console->CommandScrollBack = 0;
478 console->OutputScreen = DisplayScreen;
479 console->Prompt = CON_DEFAULT_PROMPT;
480 console->HideKey = CON_DEFAULT_HIDEKEY;
482 /* make sure that the size of the console is valid */
483 if(w > console->OutputScreen->sc_w || w < Font->ft_w * 32)
484 w = console->OutputScreen->sc_w;
485 if(h > console->OutputScreen->sc_h || h < Font->ft_h)
486 h = console->OutputScreen->sc_h;
488 /* load the console surface */
489 console->ConsoleSurface = gr_create_canvas(w, h);
491 /* Load the consoles font */
493 grs_canvas *canv_save;
495 canv_save = grd_curcanv;
496 gr_set_current_canvas(console->ConsoleSurface);
497 gr_set_curfont(Font);
498 gr_set_fontcolor(gr_getcolor(63,63,63), -1);
499 gr_set_current_canvas(canv_save);
503 /* Load the dirty rectangle for user input */
504 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
506 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
509 /* calculate the number of visible characters in the command line */
510 console->VChars = (w - CON_CHAR_BORDER) / console->ConsoleSurface->cv_font->ft_w;
511 if(console->VChars > CON_CHARS_PER_LINE)
512 console->VChars = CON_CHARS_PER_LINE;
514 /* We would like to have a minumum # of lines to guarentee we don't create a memory error */
515 if(h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h) > lines)
516 console->LineBuffer = h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
518 console->LineBuffer = lines;
521 console->ConsoleLines = (char **)d_malloc(sizeof(char *) * console->LineBuffer);
522 console->CommandLines = (char **)d_malloc(sizeof(char *) * console->LineBuffer);
523 for(loop = 0; loop <= console->LineBuffer - 1; loop++) {
524 console->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
525 console->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
527 memset(console->Command, 0, CON_CHARS_PER_LINE);
528 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
529 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
530 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
533 CON_Out("Console initialised.");
534 CON_NewLineConsole();
537 /* Makes the console visible */
538 void CON_Show(void) {
539 console->Visible = CON_OPENING;
543 /* Hides the console (make it invisible) */
544 void CON_Hide(void) {
545 console->Visible = CON_CLOSING;
548 /* tells wether the console is visible or not */
549 int CON_isVisible(void) {
550 return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
553 /* Frees all the memory loaded by the console */
554 void CON_Free(void) {
557 for(i = 0; i <= console->LineBuffer - 1; i++) {
558 d_free(console->ConsoleLines[i]);
559 d_free(console->CommandLines[i]);
561 d_free(console->ConsoleLines);
562 d_free(console->CommandLines);
564 console->ConsoleLines = NULL;
565 console->CommandLines = NULL;
567 gr_free_canvas(console->ConsoleSurface);
568 console->ConsoleSurface = NULL;
570 if (console->BackgroundImage)
571 gr_free_bitmap(console->BackgroundImage);
572 console->BackgroundImage = NULL;
574 gr_free_bitmap(console->InputBackground);
575 console->InputBackground = NULL;
581 /* Increments the console lines */
582 void CON_NewLineConsole(void) {
586 temp = console->ConsoleLines[console->LineBuffer - 1];
588 for(loop = console->LineBuffer - 1; loop > 0; loop--)
589 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
591 console->ConsoleLines[0] = temp;
593 memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
594 if(console->TotalConsoleLines < console->LineBuffer - 1)
595 console->TotalConsoleLines++;
597 //Now adjust the ConsoleScrollBack
598 //dont scroll if not at bottom
599 if(console->ConsoleScrollBack != 0)
600 console->ConsoleScrollBack++;
602 if(console->ConsoleScrollBack > console->LineBuffer-1)
603 console->ConsoleScrollBack = console->LineBuffer-1;
608 /* Increments the command lines */
609 void CON_NewLineCommand(void) {
613 temp = console->CommandLines[console->LineBuffer - 1];
616 for(loop = console->LineBuffer - 1; loop > 0; loop--)
617 console->CommandLines[loop] = console->CommandLines[loop - 1];
619 console->CommandLines[0] = temp;
621 memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
622 if(console->TotalCommands < console->LineBuffer - 1)
623 console->TotalCommands++;
626 /* Draws the command line the user is typing in to the screen */
627 /* completely rewritten by C.Wacha */
628 void DrawCommandLine() {
632 grs_font* CurrentFont;
634 static unsigned int LastBlinkTime = 0; /* Last time the consoles cursor blinked */
635 static int LastCursorPos = 0; // Last Cursor Position
636 static int Blink = 0; /* Is the cursor currently blinking */
637 grs_canvas *canv_save;
640 commandbuffer = console->VChars - strlen(console->Prompt)-1; // -1 to make cursor visible
643 CurrentFont = console->ConsoleSurface->cv_font;
646 //Concatenate the left and right side to command
647 strcpy(console->Command, console->LCommand);
648 strncat(console->Command, console->RCommand, strlen(console->RCommand));
650 //calculate display offset from current cursor position
651 if(console->Offset < console->CursorPos - commandbuffer)
652 console->Offset = console->CursorPos - commandbuffer;
653 if(console->Offset > console->CursorPos)
654 console->Offset = console->CursorPos;
656 //first add prompt to visible part
657 strcpy(console->VCommand, console->Prompt);
659 //then add the visible part of the command
660 strncat(console->VCommand, &console->Command[console->Offset], strlen(&console->Command[console->Offset]));
662 //now display the result
665 //once again we're drawing text, so in OpenGL context we need to temporarily set up
666 //software-mode transparency.
667 if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
668 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
669 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
673 canv_save = grd_curcanv;
674 gr_set_current_canvas(console->ConsoleSurface);
676 //first of all restore InputBackground
677 gr_bitmap(0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->InputBackground);
680 orig_color = FG_COLOR;
681 gr_string(CON_CHAR_BORDER, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->VCommand);
682 FG_COLOR = orig_color;
684 //at last add the cursor
685 //check if the blink period is over
686 if(get_msecs() > LastBlinkTime) {
687 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
694 //check if cursor has moved - if yes display cursor anyway
695 if(console->CursorPos != LastCursorPos) {
696 LastCursorPos = console->CursorPos;
697 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
702 int prompt_width, cmd_width, h, w;
704 gr_get_string_size(console->Prompt, &prompt_width, &h, &w);
705 gr_get_string_size(console->LCommand + console->Offset, &cmd_width, &h, &w);
706 x = CON_CHAR_BORDER + prompt_width + cmd_width;
707 orig_color = FG_COLOR;
709 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
711 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
712 FG_COLOR = orig_color;
715 gr_set_current_canvas(canv_save);
719 if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
720 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
726 # define vsnprintf _vsnprintf
729 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
730 void CON_Out(const char *str, ...) {
732 //keep some space free for stuff like CON_Out("blablabla %s", console->Command);
733 char temp[CON_CHARS_PER_LINE + 128];
736 va_start(marker, str);
737 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
742 //temp now contains the complete string we want to output
743 // the only problem is that temp is maybe longer than the console
744 // width so we have to cut it into several pieces
746 if(console->ConsoleLines) {
747 while(strlen(ptemp) > console->VChars) {
748 CON_NewLineConsole();
749 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
750 console->ConsoleLines[0][console->VChars] = '\0';
751 ptemp = &ptemp[console->VChars];
753 CON_NewLineConsole();
754 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
755 console->ConsoleLines[0][console->VChars] = '\0';
762 /* Sets the alpha level of the console, 0 turns off alpha blending */
763 void CON_Alpha(unsigned char alpha) {
764 /* store alpha as state! */
765 console->ConsoleAlpha = alpha;
767 if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
769 SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
771 SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
774 // CON_UpdateConsole();
779 /* Adds background image to the console, scaled to size of console*/
780 int CON_Background(grs_bitmap *image)
782 /* Free the background from the console */
784 if (console->BackgroundImage)
785 gr_free_bitmap(console->BackgroundImage);
786 console->BackgroundImage = NULL;
788 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
793 /* Load a new background */
794 if (console->BackgroundImage)
795 gr_free_bitmap(console->BackgroundImage);
796 console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
797 gr_bitmap_scale_to(image, console->BackgroundImage);
800 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
802 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);
807 /* Sets font info for the console */
808 void CON_Font(grs_font *font, int fg, int bg)
810 grs_canvas *canv_save;
812 canv_save = grd_curcanv;
813 gr_set_current_canvas(console->ConsoleSurface);
814 gr_set_curfont(font);
815 gr_set_fontcolor(fg, bg);
816 gr_set_current_canvas(canv_save);
819 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
820 /* resizes the console, has to reset alot of stuff
821 * returns 1 on error */
822 int CON_Resize(int x, int y, int w, int h)
824 /* make sure that the size of the console is valid */
825 if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
826 w = console->OutputScreen->sc_w;
827 if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
828 h = console->OutputScreen->sc_h;
830 /* resize console surface */
831 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
832 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
834 /* Load the dirty rectangle for user input */
835 gr_free_bitmap(console->InputBackground);
836 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
838 /* Now reset some stuff dependent on the previous size */
839 console->ConsoleScrollBack = 0;
841 /* Reload the background image (for the input text area) in the console */
842 if(console->BackgroundImage) {
844 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
846 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);
850 /* restore the alpha level */
851 CON_Alpha(console->ConsoleAlpha);
856 /* Transfers the console to another screen surface, and adjusts size */
857 int CON_Transfer(grs_screen *new_outputscreen, int x, int y, int w, int h)
859 console->OutputScreen = new_outputscreen;
861 return(CON_Resize(x, y, w, h));
864 /* Sets the Prompt for console */
865 void CON_SetPrompt(char* newprompt) {
866 //check length so we can still see at least 1 char :-)
867 if(strlen(newprompt) < console->VChars)
868 console->Prompt = d_strdup(newprompt);
870 CON_Out("prompt too long. (max. %i chars)", console->VChars - 1);
873 /* Sets the key that deactivates (hides) the console. */
874 void CON_SetHideKey(int key) {
875 console->HideKey = key;
878 /* Executes the command entered */
879 void CON_Execute(char* command) {
883 void CON_TabCompletion(void) {
887 command = d_strdup(console->LCommand);
888 command = cmd_complete(command);
891 return; //no tab completion took place so return silently
894 if(j > CON_CHARS_PER_LINE - 2)
895 j = CON_CHARS_PER_LINE-1;
897 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
898 console->CursorPos = 0;
900 for(i = 0; i < j; i++) {
901 console->CursorPos++;
902 console->LCommand[i] = command[i];
904 //add a trailing space
905 console->CursorPos++;
906 console->LCommand[j] = ' ';
907 console->LCommand[j+1] = '\0';
910 void Cursor_Left(void) {
911 char temp[CON_CHARS_PER_LINE];
913 if(console->CursorPos > 0) {
914 console->CursorPos--;
915 strcpy(temp, console->RCommand);
916 strcpy(console->RCommand, &console->LCommand[strlen(console->LCommand)-1]);
917 strcat(console->RCommand, temp);
918 console->LCommand[strlen(console->LCommand)-1] = '\0';
919 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
923 void Cursor_Right(void) {
924 char temp[CON_CHARS_PER_LINE];
926 if(console->CursorPos < strlen(console->Command)) {
927 console->CursorPos++;
928 strncat(console->LCommand, console->RCommand, 1);
929 strcpy(temp, console->RCommand);
930 strcpy(console->RCommand, &temp[1]);
931 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
935 void Cursor_Home(void) {
936 char temp[CON_CHARS_PER_LINE];
938 console->CursorPos = 0;
939 strcpy(temp, console->RCommand);
940 strcpy(console->RCommand, console->LCommand);
941 strncat(console->RCommand, temp, strlen(temp));
942 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
945 void Cursor_End(void) {
946 console->CursorPos = strlen(console->Command);
947 strncat(console->LCommand, console->RCommand, strlen(console->RCommand));
948 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
951 void Cursor_Del(void) {
952 char temp[CON_CHARS_PER_LINE];
954 if(strlen(console->RCommand) > 0) {
955 strcpy(temp, console->RCommand);
956 strcpy(console->RCommand, &temp[1]);
960 void Cursor_BSpace(void) {
961 if(console->CursorPos > 0) {
962 console->CursorPos--;
964 if(console->Offset < 0)
966 console->LCommand[strlen(console->LCommand)-1] = '\0';
970 void Cursor_Add(int event)
972 if(strlen(console->Command) < CON_CHARS_PER_LINE - 1)
974 console->CursorPos++;
975 console->LCommand[strlen(console->LCommand)] = key_to_ascii(event);
976 console->LCommand[strlen(console->LCommand)] = '\0';
980 void Clear_Command(void) {
981 console->CursorPos = 0;
982 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
983 memset(console->Command, 0, CON_CHARS_PER_LINE);
984 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
985 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
988 void Clear_History(void) {
991 for(loop = 0; loop <= console->LineBuffer - 1; loop++)
992 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
995 void Command_Up(void) {
996 if(console->CommandScrollBack < console->TotalCommands - 1) {
997 /* move back a line in the command strings and copy the command to the current input string */
998 console->CommandScrollBack++;
999 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1000 console->Offset = 0;
1001 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1002 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1003 CON_UpdateConsole();
1007 void Command_Down(void) {
1008 if(console->CommandScrollBack > -1) {
1009 /* move forward a line in the command strings and copy the command to the current input string */
1010 console->CommandScrollBack--;
1011 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1012 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1013 console->Offset = 0;
1014 if(console->CommandScrollBack > -1)
1015 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1016 console->CursorPos = strlen(console->LCommand);
1017 CON_UpdateConsole();
1030 #include "pstypes.h"
1033 #include "console.h"
1037 #include "gamefont.h"
1042 int text_console_enabled = 1;
1045 #define text_console_enabled (!isvga())
1049 /* Console specific cvars */
1050 /* How discriminating we are about which messages are displayed */
1051 cvar_t con_threshold = {"con_threshold", "0",};
1053 /* Private console stuff */
1054 #define CON_NUM_LINES 40
1057 /* Initialise the console */
1060 grs_screen fake_screen;
1063 fake_screen.sc_w = 320;
1064 fake_screen.sc_h = 200;
1068 CON_Init(&fake_font, &fake_screen, CON_NUM_LINES, 0, 0, 320, 200);
1072 /* Initialise the cvars */
1073 cvar_registervariable (&con_threshold);
1075 con_initialized = 1;
1081 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
1082 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
1083 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
1085 void con_background(char *filename)
1091 gr_init_bitmap_data(&bmp);
1092 pcx_error = pcx_read_bitmap(filename, &bmp, BM_LINEAR, pal);
1093 Assert(pcx_error == PCX_ERROR_NONE);
1094 gr_remap_bitmap_good(&bmp, pal, -1, -1);
1095 CON_Background(&bmp);
1096 gr_free_bitmap_data(&bmp);
1100 void con_init_gfx(void)
1102 CON_Font(SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1103 CON_Transfer(grd_curscreen, 0, 0, SWIDTH, SHEIGHT / 2);
1105 con_background(CON_BG);
1109 void con_resize(void)
1111 CON_Font(SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1112 CON_Resize(0, 0, SWIDTH, SHEIGHT / 2);
1113 con_background(CON_BG);
1116 /* Print a message to the console */
1117 void con_printf(int priority, char *fmt, ...)
1122 if (priority <= ((int)con_threshold.value))
1124 va_start (arglist, fmt);
1125 vsprintf (buffer, fmt, arglist);
1128 if (con_initialized)
1131 if (text_console_enabled)
1133 /* Produce a sanitised version and send it to the standard output */
1152 printf("%s", buffer);