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())
32 static ConsoleInformation *Console;
34 /* Pointer to our one console */
35 static ConsoleInformation *console;
38 void CON_UpdateOffset(void);
40 void CON_Destroy(void);
41 /*! Frees all the memory loaded by the console */
44 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
45 255 - opaque). Use this function also for OpenGL. */
46 void CON_Alpha(unsigned char alpha);
47 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
48 Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
49 void CON_AlphaGL(SDL_Surface *s, int alpha);
50 /*! Sets a background image for the console */
52 int CON_Background(grs_bitmap *image);
53 /*! Sets font info for the console */
54 void CON_Font(grs_font *font, int fg, int bg);
55 /*! Changes current position of the console */
56 void CON_Position(int x, int y);
57 /*! Beams a console to another screen surface. Needed if you want to make a Video restart in your program. This
58 function first changes the OutputScreen Pointer then calls CON_Resize to adjust the new size. */
59 int CON_Transfer(grs_screen* new_outputscreen, int x, int y, int w, int h);
60 /*! Modify the prompt of the console */
61 void CON_SetPrompt(char* newprompt);
62 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
63 ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
64 void CON_SetHideKey(int key);
65 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
66 void CON_SetHideFunction(void(*HideFunction)(void));
67 /*! Sets the callback function that is called after a console has been hidden */
68 void CON_Execute(char* command);
69 /*! Sets the callback function that is called if a command was typed in. The function could look like this:
70 void my_command_handler(char* command). @param console: the console the command
71 came from. @param command: the command string that was typed in. */
72 void CON_SetExecuteFunction(void(*CmdFunction)(char* command));
73 /*! Sets the callback tabulator completion function. char* my_tabcompletion(char* command). If Tab is
74 pressed, the function gets called with the already typed in command. my_tabcompletion then checks if if can
75 complete the command or if it should display a list of all matching commands (with CON_Out()). Returns the
76 completed command or NULL if no completion was made. */
77 void CON_SetTabCompletion(char*(*TabFunction)(char* command));
78 /*! Internal: Gets called when TAB was pressed */
79 void CON_TabCompletion(void);
80 /*! Internal: makes newline (same as printf("\n") or CON_Out("\n") ) */
81 void CON_NewLineConsole(void);
82 /*! Internal: shift command history (the one you can switch with the up/down keys) */
83 void CON_NewLineCommand(void);
84 /*! Internal: updates console after resize etc. */
85 void CON_UpdateConsole(void);
88 /*! Internal: Default Execute callback */
89 void Default_CmdFunction(char* command);
90 /*! Internal: Default TabCompletion callback */
91 char* Default_TabFunction(char* command);
92 /*! Internal: Default Hide callback */
93 void Default_HideFunction(void);
95 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
96 void DrawCommandLine();
98 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
99 void Cursor_Left(void);
100 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
101 void Cursor_Right(void);
102 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
104 void Cursor_Home(void);
105 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
106 void Cursor_End(void);
107 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
108 void Cursor_Del(void);
109 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
110 void Cursor_BSpace(void);
111 /*! Internal: Called if you type in a character (add the char to the command) */
112 void Cursor_Add(int event);
114 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
115 void Clear_Command(void);
116 /*! Internal: Called if you press Ctrl-L (deletes the History) */
117 void Clear_History(void);
119 /*! Internal: Called if you press UP key (switches through recent typed in commands */
120 void Command_Up(void);
121 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
122 void Command_Down(void);
125 /* Takes keys from the keyboard and inputs them to the console
126 If the event was not handled (i.e. WM events or unknown ctrl-shift
127 sequences) the function returns the event for further processing. */
128 int CON_Events(int event)
133 if(event & KEY_CTRLED)
136 switch(event & ~KEY_CTRLED)
155 else if(event & KEY_ALTED)
157 //the console does not handle ALT combinations!
162 //first of all, check if the console hide key was pressed
163 if(event == console->HideKey)
168 switch (event & 0xff)
174 if(event & KEY_SHIFTED)
176 console->ConsoleScrollBack = console->LineBuffer-1;
183 if(event & KEY_SHIFTED)
185 console->ConsoleScrollBack = 0;
192 console->ConsoleScrollBack += CON_LINE_SCROLL;
193 if(console->ConsoleScrollBack > console->LineBuffer-1)
194 console->ConsoleScrollBack = console->LineBuffer-1;
199 console->ConsoleScrollBack -= CON_LINE_SCROLL;
200 if(console->ConsoleScrollBack < 0)
201 console->ConsoleScrollBack = 0;
223 console->InsMode = 1-console->InsMode;
229 if(strlen(console->Command) > 0) {
230 CON_NewLineCommand();
232 // copy the input into the past commands strings
233 strcpy(console->CommandLines[0], console->Command);
235 // display the command including the prompt
236 CON_Out("%s%s", console->Prompt, console->Command);
239 CON_Execute(console->Command);
240 //printf("Command: %s\n", console->Command);
243 console->CommandScrollBack = -1;
251 if (key_to_ascii(event) == 255)
265 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
266 * specified value. Preconditions: the surface in question is RGBA.
267 * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
268 void CON_AlphaGL(SDL_Surface *s, int alpha) {
273 SDL_PixelFormat *format;
274 static char errorPrinted = 0;
277 /* debugging assertions -- these slow you down, but hey, crashing sucks */
279 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
283 /* clamp alpha value to 0...255 */
284 if(alpha < SDL_ALPHA_TRANSPARENT)
285 val = SDL_ALPHA_TRANSPARENT;
286 else if(alpha > SDL_ALPHA_OPAQUE)
287 val = SDL_ALPHA_OPAQUE;
291 /* loop over alpha channels of each pixel, setting them appropriately. */
295 switch (format->BytesPerPixel) {
297 /* 16-bit surfaces don't seem to support alpha channels. */
300 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
304 /* we can do this very quickly in 32-bit mode. 24-bit is more
305 * difficult. And since 24-bit mode is reall the same as 32-bit,
306 * so it usually ends up taking this route too. Win! Unroll loop
307 * and use pointer arithmetic for extra speed. */
308 int numpixels = h * (w << 2);
309 Uint8 *pix = (Uint8 *) (s->pixels);
310 Uint8 *last = pix + numpixels;
312 if((numpixels & 0x7) == 0)
313 for(pixel = pix + 3; pixel < last; pixel += 32)
314 *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
316 for(pixel = pix + 3; pixel < last; pixel += 4)
321 /* we have no choice but to do this slowly. <sigh> */
322 for(y = 0; y < h; ++y)
323 for(x = 0; x < w; ++x) {
325 /* Lock the surface for direct access to the pixels */
326 if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
327 PRINT_ERROR("Can't lock surface: ");
328 fprintf(stderr, "%s\n", SDL_GetError());
331 pixel = DT_GetPixel(s, x, y);
334 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
335 pixel = SDL_MapRGBA(format, r, g, b, val);
336 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
337 DT_PutPixel(s, x, y, pixel);
339 /* unlock surface again */
341 SDL_UnlockSurface(s);
349 /* Updates the console buffer */
350 void CON_UpdateConsole(void) {
354 grs_canvas *canv_save;
360 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
364 Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
366 canv_save = grd_curcanv;
367 gr_set_current_canvas(console->ConsoleSurface);
370 SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
376 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
377 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
380 /* draw the background image if there is one */
381 if(console->BackgroundImage)
382 gr_bitmap(0, 0, console->BackgroundImage);
384 /* Draw the text from the back buffers, calculate in the scrollback from the user
385 * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
386 * for the font, and then clear it when we're done.
389 if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
390 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
391 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
395 //now draw text from last but second line to top
396 for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
397 if(console->ConsoleScrollBack != 0 && loop == 0)
398 for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
400 orig_color = FG_COLOR;
401 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);
402 FG_COLOR = orig_color;
406 orig_color = FG_COLOR;
407 gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
408 FG_COLOR = orig_color;
412 gr_set_current_canvas(canv_save);
415 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
416 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
420 void CON_UpdateOffset(void) {
424 switch(console->Visible) {
426 console->RaiseOffset -= CON_OPENCLOSE_SPEED;
427 if(console->RaiseOffset <= 0) {
428 console->RaiseOffset = 0;
429 console->Visible = CON_CLOSED;
433 console->RaiseOffset += CON_OPENCLOSE_SPEED;
434 if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
435 console->RaiseOffset = console->ConsoleSurface->cv_h;
436 console->Visible = CON_OPEN;
445 /* Draws the console buffer to the screen if the console is "visible" */
446 void CON_DrawConsole(void) {
447 grs_canvas *canv_save;
453 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
454 if(console->Visible == CON_CLOSED)
457 /* Update the scrolling offset */
460 /* Update the command line since it has a blinking cursor */
464 /* before drawing, make sure the alpha channel of the console surface is set
465 * properly. (sigh) I wish we didn't have to do this every frame... */
466 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
467 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
470 canv_save = grd_curcanv;
471 gr_set_current_canvas(&console->OutputScreen->sc_canvas);
473 clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
475 gr_bitmap(console->DispX, console->DispY, clip);
476 gr_free_sub_bitmap(clip);
479 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
480 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
483 gr_set_current_canvas(canv_save);
487 /* Initializes the console */
488 ConsoleInformation *CON_Init(grs_font *Font, grs_screen *DisplayScreen, int lines, int x, int y, int w, int h)
491 ConsoleInformation *newinfo;
494 /* Create a new console struct and init it. */
495 if((newinfo = (ConsoleInformation *) d_malloc(sizeof(ConsoleInformation))) == NULL) {
496 //PRINT_ERROR("Could not allocate the space for a new console info struct.\n");
499 newinfo->Visible = CON_CLOSED;
500 newinfo->RaiseOffset = 0;
501 newinfo->ConsoleLines = NULL;
502 newinfo->CommandLines = NULL;
503 newinfo->TotalConsoleLines = 0;
504 newinfo->ConsoleScrollBack = 0;
505 newinfo->TotalCommands = 0;
506 newinfo->BackgroundImage = NULL;
508 newinfo->ConsoleAlpha = SDL_ALPHA_OPAQUE;
511 newinfo->InsMode = 1;
512 newinfo->CursorPos = 0;
513 newinfo->CommandScrollBack = 0;
514 newinfo->OutputScreen = DisplayScreen;
515 newinfo->Prompt = CON_DEFAULT_PROMPT;
516 newinfo->HideKey = CON_DEFAULT_HIDEKEY;
518 CON_SetExecuteFunction(Default_CmdFunction);
519 CON_SetTabCompletion(Default_TabFunction);
520 CON_SetHideFunction(Default_HideFunction);
522 /* make sure that the size of the console is valid */
523 if(w > newinfo->OutputScreen->sc_w || w < Font->ft_w * 32)
524 w = newinfo->OutputScreen->sc_w;
525 if(h > newinfo->OutputScreen->sc_h || h < Font->ft_h)
526 h = newinfo->OutputScreen->sc_h;
527 if(x < 0 || x > newinfo->OutputScreen->sc_w - w)
531 if(y < 0 || y > newinfo->OutputScreen->sc_h - h)
536 /* load the console surface */
537 newinfo->ConsoleSurface = gr_create_canvas(w, h);
539 /* Load the consoles font */
541 grs_canvas *canv_save;
543 canv_save = grd_curcanv;
544 gr_set_current_canvas(newinfo->ConsoleSurface);
545 gr_set_curfont(Font);
546 gr_set_fontcolor(gr_getcolor(63,63,63), -1);
547 gr_set_current_canvas(canv_save);
551 /* Load the dirty rectangle for user input */
552 newinfo->InputBackground = gr_create_bitmap(w, newinfo->ConsoleSurface->cv_font->ft_h);
554 SDL_FillRect(newinfo->InputBackground, NULL, SDL_MapRGBA(newinfo->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
557 /* calculate the number of visible characters in the command line */
558 newinfo->VChars = (w - CON_CHAR_BORDER) / newinfo->ConsoleSurface->cv_font->ft_w;
559 if(newinfo->VChars > CON_CHARS_PER_LINE)
560 newinfo->VChars = CON_CHARS_PER_LINE;
562 /* We would like to have a minumum # of lines to guarentee we don't create a memory error */
563 if(h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h) > lines)
564 newinfo->LineBuffer = h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h);
566 newinfo->LineBuffer = lines;
569 newinfo->ConsoleLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
570 newinfo->CommandLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
571 for(loop = 0; loop <= newinfo->LineBuffer - 1; loop++) {
572 newinfo->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
573 newinfo->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
575 memset(newinfo->Command, 0, CON_CHARS_PER_LINE);
576 memset(newinfo->LCommand, 0, CON_CHARS_PER_LINE);
577 memset(newinfo->RCommand, 0, CON_CHARS_PER_LINE);
578 memset(newinfo->VCommand, 0, CON_CHARS_PER_LINE);
581 CON_Out("Console initialised.");
582 CON_NewLineConsole();
583 //CON_ListCommands();
588 /* Makes the console visible */
589 void CON_Show(void) {
591 console->Visible = CON_OPENING;
596 /* Hides the console (make it invisible) */
597 void CON_Hide(void) {
599 console->Visible = CON_CLOSING;
600 console->HideFunction();
603 /* tells wether the console is visible or not */
604 int CON_isVisible(void) {
607 return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
610 /* Frees all the memory loaded by the console */
611 void CON_Destroy(void) {
615 /* Frees all the memory loaded by the console */
616 void CON_Free(void) {
622 //CON_DestroyCommands();
623 for(i = 0; i <= console->LineBuffer - 1; i++) {
624 d_free(console->ConsoleLines[i]);
625 d_free(console->CommandLines[i]);
627 d_free(console->ConsoleLines);
628 d_free(console->CommandLines);
630 console->ConsoleLines = NULL;
631 console->CommandLines = NULL;
633 gr_free_canvas(console->ConsoleSurface);
634 console->ConsoleSurface = NULL;
636 if (console->BackgroundImage)
637 gr_free_bitmap(console->BackgroundImage);
638 console->BackgroundImage = NULL;
640 gr_free_bitmap(console->InputBackground);
641 console->InputBackground = NULL;
647 /* Increments the console lines */
648 void CON_NewLineConsole(void) {
655 temp = console->ConsoleLines[console->LineBuffer - 1];
657 for(loop = console->LineBuffer - 1; loop > 0; loop--)
658 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
660 console->ConsoleLines[0] = temp;
662 memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
663 if(console->TotalConsoleLines < console->LineBuffer - 1)
664 console->TotalConsoleLines++;
666 //Now adjust the ConsoleScrollBack
667 //dont scroll if not at bottom
668 if(console->ConsoleScrollBack != 0)
669 console->ConsoleScrollBack++;
671 if(console->ConsoleScrollBack > console->LineBuffer-1)
672 console->ConsoleScrollBack = console->LineBuffer-1;
677 /* Increments the command lines */
678 void CON_NewLineCommand(void) {
685 temp = console->CommandLines[console->LineBuffer - 1];
688 for(loop = console->LineBuffer - 1; loop > 0; loop--)
689 console->CommandLines[loop] = console->CommandLines[loop - 1];
691 console->CommandLines[0] = temp;
693 memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
694 if(console->TotalCommands < console->LineBuffer - 1)
695 console->TotalCommands++;
698 /* Draws the command line the user is typing in to the screen */
699 /* completely rewritten by C.Wacha */
700 void DrawCommandLine() {
704 grs_font* CurrentFont;
706 static unsigned int LastBlinkTime = 0; /* Last time the consoles cursor blinked */
707 static int LastCursorPos = 0; // Last Cursor Position
708 static int Blink = 0; /* Is the cursor currently blinking */
709 grs_canvas *canv_save;
712 commandbuffer = console->VChars - strlen(console->Prompt)-1; // -1 to make cursor visible
715 CurrentFont = console->ConsoleSurface->cv_font;
718 //Concatenate the left and right side to command
719 strcpy(console->Command, console->LCommand);
720 strncat(console->Command, console->RCommand, strlen(console->RCommand));
722 //calculate display offset from current cursor position
723 if(console->Offset < console->CursorPos - commandbuffer)
724 console->Offset = console->CursorPos - commandbuffer;
725 if(console->Offset > console->CursorPos)
726 console->Offset = console->CursorPos;
728 //first add prompt to visible part
729 strcpy(console->VCommand, console->Prompt);
731 //then add the visible part of the command
732 strncat(console->VCommand, &console->Command[console->Offset], strlen(&console->Command[console->Offset]));
734 //now display the result
737 //once again we're drawing text, so in OpenGL context we need to temporarily set up
738 //software-mode transparency.
739 if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
740 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
741 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
745 canv_save = grd_curcanv;
746 gr_set_current_canvas(console->ConsoleSurface);
748 //first of all restore InputBackground
749 gr_bitmap(0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->InputBackground);
752 orig_color = FG_COLOR;
753 gr_string(CON_CHAR_BORDER, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->VCommand);
754 FG_COLOR = orig_color;
756 //at last add the cursor
757 //check if the blink period is over
758 if(get_msecs() > LastBlinkTime) {
759 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
766 //check if cursor has moved - if yes display cursor anyway
767 if(console->CursorPos != LastCursorPos) {
768 LastCursorPos = console->CursorPos;
769 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
774 int prompt_width, cmd_width, h, w;
776 gr_get_string_size(console->Prompt, &prompt_width, &h, &w);
777 gr_get_string_size(console->LCommand + console->Offset, &cmd_width, &h, &w);
778 x = CON_CHAR_BORDER + prompt_width + cmd_width;
779 orig_color = FG_COLOR;
781 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
783 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
784 FG_COLOR = orig_color;
787 gr_set_current_canvas(canv_save);
791 if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
792 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
798 # define vsnprintf _vsnprintf
801 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
802 void CON_Out(const char *str, ...) {
804 //keep some space free for stuff like CON_Out("blablabla %s", console->Command);
805 char temp[CON_CHARS_PER_LINE + 128];
811 va_start(marker, str);
812 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
817 //temp now contains the complete string we want to output
818 // the only problem is that temp is maybe longer than the console
819 // width so we have to cut it into several pieces
821 if(console->ConsoleLines) {
822 while(strlen(ptemp) > console->VChars) {
823 CON_NewLineConsole();
824 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
825 console->ConsoleLines[0][console->VChars] = '\0';
826 ptemp = &ptemp[console->VChars];
828 CON_NewLineConsole();
829 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
830 console->ConsoleLines[0][console->VChars] = '\0';
834 /* And print to stdout */
835 //printf("%s\n", temp);
840 /* Sets the alpha level of the console, 0 turns off alpha blending */
841 void CON_Alpha(unsigned char alpha) {
845 /* store alpha as state! */
846 console->ConsoleAlpha = alpha;
848 if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
850 SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
852 SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
855 // CON_UpdateConsole();
860 /* Adds background image to the console, scaled to size of console*/
861 int CON_Background(grs_bitmap *image)
866 /* Free the background from the console */
868 if (console->BackgroundImage)
869 gr_free_bitmap(console->BackgroundImage);
870 console->BackgroundImage = NULL;
872 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
877 /* Load a new background */
878 if (console->BackgroundImage)
879 gr_free_bitmap(console->BackgroundImage);
880 console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
881 gr_bitmap_scale_to(image, console->BackgroundImage);
884 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
886 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);
891 /* Sets font info for the console */
892 void CON_Font(grs_font *font, int fg, int bg)
894 grs_canvas *canv_save;
896 canv_save = grd_curcanv;
897 gr_set_current_canvas(console->ConsoleSurface);
898 gr_set_curfont(font);
899 gr_set_fontcolor(fg, bg);
900 gr_set_current_canvas(canv_save);
903 /* takes a new x and y of the top left of the console window */
904 void CON_Position(int x, int y) {
908 if(x < 0 || x > console->OutputScreen->sc_w - console->ConsoleSurface->cv_w)
913 if(y < 0 || y > console->OutputScreen->sc_h - console->ConsoleSurface->cv_h)
919 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
920 /* resizes the console, has to reset alot of stuff
921 * returns 1 on error */
922 int CON_Resize(int x, int y, int w, int h)
927 /* make sure that the size of the console is valid */
928 if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
929 w = console->OutputScreen->sc_w;
930 if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
931 h = console->OutputScreen->sc_h;
932 if(x < 0 || x > console->OutputScreen->sc_w - w)
936 if(y < 0 || y > console->OutputScreen->sc_h - h)
941 /* resize console surface */
942 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
943 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
945 /* Load the dirty rectangle for user input */
946 gr_free_bitmap(console->InputBackground);
947 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
949 /* Now reset some stuff dependent on the previous size */
950 console->ConsoleScrollBack = 0;
952 /* Reload the background image (for the input text area) in the console */
953 if(console->BackgroundImage) {
955 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
957 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);
961 /* restore the alpha level */
962 CON_Alpha(console->ConsoleAlpha);
967 /* Transfers the console to another screen surface, and adjusts size */
968 int CON_Transfer(grs_screen *new_outputscreen, int x, int y, int w, int h)
973 console->OutputScreen = new_outputscreen;
975 return(CON_Resize(x, y, w, h));
978 /* Sets the Prompt for console */
979 void CON_SetPrompt(char* newprompt) {
983 //check length so we can still see at least 1 char :-)
984 if(strlen(newprompt) < console->VChars)
985 console->Prompt = d_strdup(newprompt);
987 CON_Out("prompt too long. (max. %i chars)", console->VChars - 1);
990 /* Sets the key that deactivates (hides) the console. */
991 void CON_SetHideKey(int key) {
993 console->HideKey = key;
996 void CON_SetHideFunction(void(*HideFunction)(void)) {
998 console->HideFunction = HideFunction;
1001 void Default_HideFunction(void) {
1004 /* Executes the command entered */
1005 void CON_Execute(char* command) {
1007 console->CmdFunction(command);
1010 void CON_SetExecuteFunction(void(*CmdFunction)(char* command)) {
1012 console->CmdFunction = CmdFunction;
1015 void Default_CmdFunction(char* command) {
1016 CON_Out(" No CommandFunction registered");
1017 CON_Out(" use 'CON_SetExecuteFunction' to register one");
1019 CON_Out("Unknown Command \"%s\"", command);
1022 void CON_SetTabCompletion(char*(*TabFunction)(char* command)) {
1024 console->TabFunction = TabFunction;
1027 void CON_TabCompletion(void) {
1034 command = d_strdup(console->LCommand);
1035 command = console->TabFunction(command);
1038 return; //no tab completion took place so return silently
1040 j = strlen(command);
1041 if(j > CON_CHARS_PER_LINE - 2)
1042 j = CON_CHARS_PER_LINE-1;
1044 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1045 console->CursorPos = 0;
1047 for(i = 0; i < j; i++) {
1048 console->CursorPos++;
1049 console->LCommand[i] = command[i];
1051 //add a trailing space
1052 console->CursorPos++;
1053 console->LCommand[j] = ' ';
1054 console->LCommand[j+1] = '\0';
1057 char* Default_TabFunction(char* command) {
1058 CON_Out(" No TabFunction registered");
1059 CON_Out(" use 'CON_SetTabCompletion' to register one");
1064 void Cursor_Left(void) {
1065 char temp[CON_CHARS_PER_LINE];
1067 if(console->CursorPos > 0) {
1068 console->CursorPos--;
1069 strcpy(temp, console->RCommand);
1070 strcpy(console->RCommand, &console->LCommand[strlen(console->LCommand)-1]);
1071 strcat(console->RCommand, temp);
1072 console->LCommand[strlen(console->LCommand)-1] = '\0';
1073 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
1077 void Cursor_Right(void) {
1078 char temp[CON_CHARS_PER_LINE];
1080 if(console->CursorPos < strlen(console->Command)) {
1081 console->CursorPos++;
1082 strncat(console->LCommand, console->RCommand, 1);
1083 strcpy(temp, console->RCommand);
1084 strcpy(console->RCommand, &temp[1]);
1085 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
1089 void Cursor_Home(void) {
1090 char temp[CON_CHARS_PER_LINE];
1092 console->CursorPos = 0;
1093 strcpy(temp, console->RCommand);
1094 strcpy(console->RCommand, console->LCommand);
1095 strncat(console->RCommand, temp, strlen(temp));
1096 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1099 void Cursor_End(void) {
1100 console->CursorPos = strlen(console->Command);
1101 strncat(console->LCommand, console->RCommand, strlen(console->RCommand));
1102 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1105 void Cursor_Del(void) {
1106 char temp[CON_CHARS_PER_LINE];
1108 if(strlen(console->RCommand) > 0) {
1109 strcpy(temp, console->RCommand);
1110 strcpy(console->RCommand, &temp[1]);
1114 void Cursor_BSpace(void) {
1115 if(console->CursorPos > 0) {
1116 console->CursorPos--;
1118 if(console->Offset < 0)
1119 console->Offset = 0;
1120 console->LCommand[strlen(console->LCommand)-1] = '\0';
1124 void Cursor_Add(int event)
1126 if(strlen(console->Command) < CON_CHARS_PER_LINE - 1)
1128 console->CursorPos++;
1129 console->LCommand[strlen(console->LCommand)] = key_to_ascii(event);
1130 console->LCommand[strlen(console->LCommand)] = '\0';
1134 void Clear_Command(void) {
1135 console->CursorPos = 0;
1136 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
1137 memset(console->Command, 0, CON_CHARS_PER_LINE);
1138 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1139 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1142 void Clear_History(void) {
1145 for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1146 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1149 void Command_Up(void) {
1150 if(console->CommandScrollBack < console->TotalCommands - 1) {
1151 /* move back a line in the command strings and copy the command to the current input string */
1152 console->CommandScrollBack++;
1153 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1154 console->Offset = 0;
1155 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1156 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1157 CON_UpdateConsole();
1161 void Command_Down(void) {
1162 if(console->CommandScrollBack > -1) {
1163 /* move forward a line in the command strings and copy the command to the current input string */
1164 console->CommandScrollBack--;
1165 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1166 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1167 console->Offset = 0;
1168 if(console->CommandScrollBack > -1)
1169 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1170 console->CursorPos = strlen(console->LCommand);
1171 CON_UpdateConsole();
1184 #include "pstypes.h"
1187 #include "console.h"
1191 #include "gamefont.h"
1196 int text_console_enabled = 1;
1199 #define text_console_enabled (!isvga())
1202 int Console_open = 0;
1204 /* Console specific cvars */
1205 /* How discriminating we are about which messages are displayed */
1206 cvar_t con_threshold = {"con_threshold", "0",};
1208 /* Private console stuff */
1209 #define CON_NUM_LINES 40
1211 static int con_initialized;
1213 void con_parse(char *command);
1217 /* Free the console */
1220 if (con_initialized)
1222 con_initialized = 0;
1226 /* Initialise the console */
1229 grs_screen fake_screen;
1232 fake_screen.sc_w = 320;
1233 fake_screen.sc_h = 200;
1237 Console = CON_Init(&fake_font, &fake_screen, CON_NUM_LINES, 0, 0, 320, 200);
1240 CON_SetExecuteFunction(con_parse);
1241 CON_SetHideFunction(con_hide);
1246 /* Initialise the cvars */
1247 cvar_registervariable (&con_threshold);
1249 con_initialized = 1;
1255 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
1256 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
1257 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
1259 void con_background(char *filename)
1265 gr_init_bitmap_data(&bmp);
1266 pcx_error = pcx_read_bitmap(filename, &bmp, BM_LINEAR, pal);
1267 Assert(pcx_error == PCX_ERROR_NONE);
1268 gr_remap_bitmap_good(&bmp, pal, -1, -1);
1269 CON_Background(&bmp);
1270 gr_free_bitmap_data(&bmp);
1274 void con_init_gfx(void)
1276 CON_Font(SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1277 CON_Transfer(grd_curscreen, 0, 0, SWIDTH, SHEIGHT / 2);
1279 con_background(CON_BG);
1283 void con_resize(void)
1285 CON_Font(SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1286 CON_Resize(0, 0, SWIDTH, SHEIGHT / 2);
1287 con_background(CON_BG);
1290 /* Print a message to the console */
1291 void con_printf(int priority, char *fmt, ...)
1296 if (priority <= ((int)con_threshold.value))
1298 va_start (arglist, fmt);
1299 vsprintf (buffer, fmt, arglist);
1302 if (con_initialized)
1305 /* for (i=0; i<l; i+=CON_LINE_LEN,con_line++)
1307 memcpy(con_display, &buffer[i], min(80, l-i));
1310 if (text_console_enabled)
1312 /* Produce a sanitised version and send it to the standard output */
1331 printf("%s", buffer);
1336 /* Check for new console input. If it's there, use it */
1337 void con_update(void)
1343 int con_events(int key)
1345 return CON_Events(key);
1349 /* Draw the console */
1355 /* Show the console */
1367 void con_parse(char *command)