]> icculus.org git repositories - btb/d2x.git/blob - main/console.c
merge console init functions
[btb/d2x.git] / main / console.c
1 /*
2  * Code for controlling the console
3  *  Based on an old version of SDL_Console
4  *
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>
8  *
9  *  This is free, just be sure to give us credit when using it
10  *  in any of your programs.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #include <conf.h>
15 #endif
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #ifndef _WIN32_WCE
22 #include <fcntl.h>
23 #endif
24 #include <ctype.h>
25
26 #include "console.h"
27
28 #include "u_mem.h"
29 #include "gr.h"
30 #include "timer.h"
31 #include "pstypes.h"
32 #include "error.h"
33 #include "cvar.h"
34 #include "gamefont.h"
35 #include "pcx.h"
36 #include "cfile.h"
37
38
39 #ifndef __MSDOS__
40 int text_console_enabled = 1;
41 #else
42 int isvga();
43 #define text_console_enabled (!isvga())
44 #endif
45
46
47 /* Console specific cvars */
48 /* How discriminating we are about which messages are displayed */
49 cvar_t con_threshold = {"con_threshold", "0",};
50
51 /* Private console stuff */
52 #define CON_NUM_LINES 40
53
54 #define FG_COLOR    grd_curcanv->cv_font_fg_color
55 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
56
57 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
58 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
59 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
60
61
62 /* our one console */
63 static ConsoleInformation Console;
64 #define console (&Console)
65
66 /* console is ready to be written to */
67 static int con_initialized;
68
69
70 /* Internals */
71 void CON_UpdateOffset(void);
72 /*! Frees all the memory loaded by the console */
73 void CON_Free(void);
74 #if 0
75 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
76  255 - opaque). Use this function also for OpenGL. */
77 void CON_Alpha(unsigned char alpha);
78 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
79  Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
80 void CON_AlphaGL(SDL_Surface *s, int alpha);
81 /*! Sets a background image for the console */
82 #endif
83 int CON_Background(grs_bitmap *image);
84 /*! Sets font info for the console */
85 void CON_Font(grs_font *font, int fg, int bg);
86 /*! Beams a console to another screen surface. Needed if you want to make a Video restart in your program. This
87  function first changes the OutputScreen Pointer then calls CON_Resize to adjust the new size. */
88 int CON_Transfer(grs_screen* new_outputscreen, int x, int y, int w, int h);
89 /*! Modify the prompt of the console */
90 void CON_SetPrompt(char* newprompt);
91 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
92  ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
93 void CON_SetHideKey(int key);
94 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
95 void CON_Execute(char* command);
96 /*! Internal: Gets called when TAB was pressed */
97 void CON_TabCompletion(void);
98 /*! Internal: makes newline (same as printf("\n") or CON_Out("\n") ) */
99 void CON_NewLineConsole(void);
100 /*! Internal: shift command history (the one you can switch with the up/down keys) */
101 void CON_NewLineCommand(void);
102 /*! Internal: updates console after resize etc. */
103 void CON_UpdateConsole(void);
104
105
106 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
107 void DrawCommandLine();
108
109 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
110 void Cursor_Left(void);
111 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
112 void Cursor_Right(void);
113 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
114         of the line */
115 void Cursor_Home(void);
116 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
117 void Cursor_End(void);
118 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
119 void Cursor_Del(void);
120 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
121 void Cursor_BSpace(void);
122 /*! Internal: Called if you type in a character (add the char to the command) */
123 void Cursor_Add(int event);
124
125 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
126 void Clear_Command(void);
127 /*! Internal: Called if you press Ctrl-L (deletes the History) */
128 void Clear_History(void);
129
130 /*! Internal: Called if you press UP key (switches through recent typed in commands */
131 void Command_Up(void);
132 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
133 void Command_Down(void);
134
135
136 /*  Takes keys from the keyboard and inputs them to the console
137  If the event was not handled (i.e. WM events or unknown ctrl-shift
138  sequences) the function returns the event for further processing. */
139 int CON_Events(int event)
140 {
141         if(!CON_isVisible())
142                 return event;
143         
144         if(event & KEY_CTRLED)
145         {
146                 //CTRL pressed
147                 switch(event & ~KEY_CTRLED)
148                 {
149                         case KEY_A:
150                                 Cursor_Home();
151                                 break;
152                         case KEY_E:
153                                 Cursor_End();
154                                 break;
155                         case KEY_C:
156                                 Clear_Command();
157                                 break;
158                         case KEY_L:
159                                 Clear_History();
160                                 CON_UpdateConsole();
161                                 break;
162                         default:
163                                 return event;
164                 }
165         }
166         else if(event & KEY_ALTED)
167         {
168                 //the console does not handle ALT combinations!
169                 return event;
170         }
171         else
172         {
173                 //first of all, check if the console hide key was pressed
174                 if(event == console->HideKey)
175                 {
176                         CON_Hide();
177                         return 0;
178                 }
179                 switch (event & 0xff)
180                 {
181                         case KEY_LSHIFT:
182                         case KEY_RSHIFT:
183                                 return event;
184                         case KEY_HOME:
185                                 if(event & KEY_SHIFTED)
186                                 {
187                                         console->ConsoleScrollBack = console->LineBuffer-1;
188                                         CON_UpdateConsole();
189                                 } else {
190                                         Cursor_Home();
191                                 }
192                                 break;
193                         case KEY_END:
194                                 if(event & KEY_SHIFTED)
195                                 {
196                                         console->ConsoleScrollBack = 0;
197                                         CON_UpdateConsole();
198                                 } else {
199                                         Cursor_End();
200                                 }
201                                 break;
202                         case KEY_PAGEUP:
203                                 console->ConsoleScrollBack += CON_LINE_SCROLL;
204                                 if(console->ConsoleScrollBack > console->LineBuffer-1)
205                                         console->ConsoleScrollBack = console->LineBuffer-1;
206                                 
207                                 CON_UpdateConsole();
208                                 break;
209                         case KEY_PAGEDOWN:
210                                 console->ConsoleScrollBack -= CON_LINE_SCROLL;
211                                 if(console->ConsoleScrollBack < 0)
212                                         console->ConsoleScrollBack = 0;
213                                 CON_UpdateConsole();
214                                 break;
215                         case KEY_UP:
216                                 Command_Up();
217                                 break;
218                         case KEY_DOWN:
219                                 Command_Down();
220                                 break;
221                         case KEY_LEFT:
222                                 Cursor_Left();
223                                 break;
224                         case KEY_RIGHT:
225                                 Cursor_Right();
226                                 break;
227                         case KEY_BACKSP:
228                                 Cursor_BSpace();
229                                 break;
230                         case KEY_DELETE:
231                                 Cursor_Del();
232                                 break;
233                         case KEY_INSERT:
234                                 console->InsMode = 1-console->InsMode;
235                                 break;
236                         case KEY_TAB:
237                                 CON_TabCompletion();
238                                 break;
239                         case KEY_ENTER:
240                                 if(strlen(console->Command) > 0) {
241                                         CON_NewLineCommand();
242                                         
243                                         // copy the input into the past commands strings
244                                         strcpy(console->CommandLines[0], console->Command);
245                                         
246                                         // display the command including the prompt
247                                         CON_Out("%s%s", console->Prompt, console->Command);
248                                         CON_UpdateConsole();
249                                         
250                                         CON_Execute(console->Command);
251                                         
252                                         Clear_Command();
253                                         console->CommandScrollBack = -1;
254                                 }
255                                 break;
256                         case KEY_LAPOSTRO:
257                                 //deactivate Console
258                                 CON_Hide();
259                                 return 0;
260                         default:
261                                 if (key_to_ascii(event) == 255)
262                                         break;
263                                 if(console->InsMode)
264                                         Cursor_Add(event);
265                                 else {
266                                         Cursor_Add(event);
267                                         Cursor_Del();
268                                 }
269                 }
270         }
271         return 0;
272 }
273
274 #if 0
275 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
276  * specified value.  Preconditions: the surface in question is RGBA.
277  * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
278 void CON_AlphaGL(SDL_Surface *s, int alpha) {
279         Uint8 val;
280         int x, y, w, h;
281         Uint32 pixel;
282         Uint8 r, g, b, a;
283         SDL_PixelFormat *format;
284         static char errorPrinted = 0;
285         
286         
287         /* debugging assertions -- these slow you down, but hey, crashing sucks */
288         if(!s) {
289                 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
290                 return;
291         }
292         
293         /* clamp alpha value to 0...255 */
294         if(alpha < SDL_ALPHA_TRANSPARENT)
295                 val = SDL_ALPHA_TRANSPARENT;
296         else if(alpha > SDL_ALPHA_OPAQUE)
297                 val = SDL_ALPHA_OPAQUE;
298         else
299                 val = alpha;
300         
301         /* loop over alpha channels of each pixel, setting them appropriately. */
302         w = s->w;
303         h = s->h;
304         format = s->format;
305         switch (format->BytesPerPixel) {
306                 case 2:
307                         /* 16-bit surfaces don't seem to support alpha channels. */
308                         if(!errorPrinted) {
309                                 errorPrinted = 1;
310                                 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
311                         }
312                         break;
313                 case 4: {
314                         /* we can do this very quickly in 32-bit mode.  24-bit is more
315                          * difficult.  And since 24-bit mode is reall the same as 32-bit,
316                          * so it usually ends up taking this route too.  Win!  Unroll loop
317                          * and use pointer arithmetic for extra speed. */
318                         int numpixels = h * (w << 2);
319                         Uint8 *pix = (Uint8 *) (s->pixels);
320                         Uint8 *last = pix + numpixels;
321                         Uint8 *pixel;
322                         if((numpixels & 0x7) == 0)
323                                 for(pixel = pix + 3; pixel < last; pixel += 32)
324                                         *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
325                         else
326                                 for(pixel = pix + 3; pixel < last; pixel += 4)
327                                         *pixel = val;
328                         break;
329                 }
330                 default:
331                         /* we have no choice but to do this slowly.  <sigh> */
332                         for(y = 0; y < h; ++y)
333                                 for(x = 0; x < w; ++x) {
334                                         char print = 0;
335                                         /* Lock the surface for direct access to the pixels */
336                                         if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
337                                                 PRINT_ERROR("Can't lock surface: ");
338                                                 fprintf(stderr, "%s\n", SDL_GetError());
339                                                 return;
340                                         }
341                                         pixel = DT_GetPixel(s, x, y);
342                                         if(x == 0 && y == 0)
343                                                 print = 1;
344                                         SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
345                                         pixel = SDL_MapRGBA(format, r, g, b, val);
346                                         SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
347                                         DT_PutPixel(s, x, y, pixel);
348                                         
349                                         /* unlock surface again */
350                                         if(SDL_MUSTLOCK(s))
351                                                 SDL_UnlockSurface(s);
352                                 }
353                         break;
354         }
355 }
356 #endif
357
358
359 /* Updates the console buffer */
360 void CON_UpdateConsole(void) {
361         int loop;
362         int loop2;
363         int Screenlines;
364         grs_canvas *canv_save;
365         short orig_color;
366         
367         /* Due to the Blits, the update is not very fast: So only update if it's worth it */
368         if(!CON_isVisible())
369                 return;
370         
371         Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
372         
373         canv_save = grd_curcanv;
374         gr_set_current_canvas(console->ConsoleSurface);
375         
376 #if 0
377         SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
378 #else
379         //gr_rect(0,0,
380 #endif
381         
382 #if 0
383         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
384                 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
385 #endif
386         
387         /* draw the background image if there is one */
388         if(console->BackgroundImage)
389                 gr_bitmap(0, 0, console->BackgroundImage);
390         
391         /* Draw the text from the back buffers, calculate in the scrollback from the user
392          * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
393          * for the font, and then clear it when we're done.
394          */
395 #if 0
396         if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
397                 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
398                 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
399         }
400 #endif
401         
402         //now draw text from last but second line to top
403         for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
404                 if(console->ConsoleScrollBack != 0 && loop == 0)
405                         for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
406                         {
407                                 orig_color = FG_COLOR;
408                                 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);
409                                 FG_COLOR = orig_color;
410                         }
411                 else
412                 {
413                         orig_color = FG_COLOR;
414                         gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
415                         FG_COLOR = orig_color;
416                 }
417         }
418         
419         gr_set_current_canvas(canv_save);
420         
421 #if 0
422         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
423                 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
424 #endif
425 }
426
427 void CON_UpdateOffset(void) {
428         switch(console->Visible) {
429                 case CON_CLOSING:
430                         console->RaiseOffset -= CON_OPENCLOSE_SPEED;
431                         if(console->RaiseOffset <= 0) {
432                                 console->RaiseOffset = 0;
433                                 console->Visible = CON_CLOSED;
434                         }
435                         break;
436                 case CON_OPENING:
437                         console->RaiseOffset += CON_OPENCLOSE_SPEED;
438                         if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
439                                 console->RaiseOffset = console->ConsoleSurface->cv_h;
440                                 console->Visible = CON_OPEN;
441                         }
442                         break;
443                 case CON_OPEN:
444                 case CON_CLOSED:
445                         break;
446         }
447 }
448
449 /* Draws the console buffer to the screen if the console is "visible" */
450 void CON_DrawConsole(void) {
451         grs_canvas *canv_save;
452         grs_bitmap *clip;
453         
454         /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
455         if(console->Visible == CON_CLOSED)
456                 return;
457         
458         /* Update the scrolling offset */
459         CON_UpdateOffset();
460         
461         /* Update the command line since it has a blinking cursor */
462         DrawCommandLine();
463         
464 #if 0
465         /* before drawing, make sure the alpha channel of the console surface is set
466          * properly.  (sigh) I wish we didn't have to do this every frame... */
467         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
468                 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
469 #endif
470         
471         canv_save = grd_curcanv;
472         gr_set_current_canvas(&console->OutputScreen->sc_canvas);
473         
474         clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
475         
476         gr_bitmap(0, 0, clip);
477         gr_free_sub_bitmap(clip);
478         
479 #if 0
480         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
481                 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
482 #endif
483         
484         gr_set_current_canvas(canv_save);
485 }
486
487
488 /* Initializes the console */
489 void CON_Init()
490 {
491         int loop;
492
493         console->Visible = CON_CLOSED;
494         console->RaiseOffset = 0;
495         console->ConsoleLines = NULL;
496         console->CommandLines = NULL;
497         console->TotalConsoleLines = 0;
498         console->ConsoleScrollBack = 0;
499         console->TotalCommands = 0;
500         console->BackgroundImage = NULL;
501 #if 0
502         console->ConsoleAlpha = SDL_ALPHA_OPAQUE;
503 #endif
504         console->Offset = 0;
505         console->InsMode = 1;
506         console->CursorPos = 0;
507         console->CommandScrollBack = 0;
508         console->OutputScreen = NULL;
509         console->Prompt = CON_DEFAULT_PROMPT;
510         console->HideKey = CON_DEFAULT_HIDEKEY;
511
512         /* load the console surface */
513         console->ConsoleSurface = NULL;
514
515         /* Load the dirty rectangle for user input */
516         console->InputBackground = NULL;
517
518         console->VChars = CON_CHARS_PER_LINE;
519         console->LineBuffer = CON_NUM_LINES;
520
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));
526         }
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);
531
532         cmd_init();
533
534         /* Initialise the cvars */
535         cvar_registervariable (&con_threshold);
536
537         con_initialized = 1;
538
539         atexit(CON_Free);
540 }
541
542
543 void CON_InitGFX(int w, int h)
544 {
545         int pcx_error;
546         grs_bitmap bmp;
547         ubyte pal[256*3];
548
549         console->OutputScreen = grd_curscreen;
550         
551         /* load the console surface */
552         console->ConsoleSurface = gr_create_canvas(w, h);
553
554         /* Load the consoles font */
555         CON_Font(SMALL_FONT, gr_getcolor(63,63,63), -1);
556
557         /* make sure that the size of the console is valid */
558         if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
559                 w = console->OutputScreen->sc_w;
560         if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
561                 h = console->OutputScreen->sc_h;
562
563         /* Load the dirty rectangle for user input */
564         console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
565 #if 0
566         SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
567 #endif
568         
569         /* calculate the number of visible characters in the command line */
570         console->VChars = (w - CON_CHAR_BORDER) / console->ConsoleSurface->cv_font->ft_w;
571         if(console->VChars > CON_CHARS_PER_LINE)
572                 console->VChars = CON_CHARS_PER_LINE;
573         
574         CON_Transfer(grd_curscreen, 0, 0, SWIDTH, SHEIGHT / 2);
575         
576         gr_init_bitmap_data(&bmp);
577         pcx_error = pcx_read_bitmap(CON_BG, &bmp, BM_LINEAR, pal);
578         Assert(pcx_error == PCX_ERROR_NONE);
579         gr_remap_bitmap_good(&bmp, pal, -1, -1);
580         CON_Background(&bmp);
581         gr_free_bitmap_data(&bmp);
582 }
583
584
585 /* Makes the console visible */
586 void CON_Show(void) {
587         console->Visible = CON_OPENING;
588         CON_UpdateConsole();
589 }
590
591 /* Hides the console (make it invisible) */
592 void CON_Hide(void) {
593         console->Visible = CON_CLOSING;
594 }
595
596 /* tells wether the console is visible or not */
597 int CON_isVisible(void) {
598         return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
599 }
600
601 /* Frees all the memory loaded by the console */
602 void CON_Free(void) {
603         int i;
604         
605         for(i = 0; i <= console->LineBuffer - 1; i++) {
606                 d_free(console->ConsoleLines[i]);
607                 d_free(console->CommandLines[i]);
608         }
609         d_free(console->ConsoleLines);
610         d_free(console->CommandLines);
611         
612         console->ConsoleLines = NULL;
613         console->CommandLines = NULL;
614         
615         gr_free_canvas(console->ConsoleSurface);
616         console->ConsoleSurface = NULL;
617         
618         if (console->BackgroundImage)
619                 gr_free_bitmap(console->BackgroundImage);
620         console->BackgroundImage = NULL;
621         
622         gr_free_bitmap(console->InputBackground);
623         console->InputBackground = NULL;
624
625         con_initialized = 0;
626 }
627
628
629 /* Increments the console lines */
630 void CON_NewLineConsole(void) {
631         int loop;
632         char* temp;
633         
634         temp = console->ConsoleLines[console->LineBuffer - 1];
635         
636         for(loop = console->LineBuffer - 1; loop > 0; loop--)
637                 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
638         
639         console->ConsoleLines[0] = temp;
640         
641         memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
642         if(console->TotalConsoleLines < console->LineBuffer - 1)
643                 console->TotalConsoleLines++;
644         
645         //Now adjust the ConsoleScrollBack
646         //dont scroll if not at bottom
647         if(console->ConsoleScrollBack != 0)
648                 console->ConsoleScrollBack++;
649         //boundaries
650         if(console->ConsoleScrollBack > console->LineBuffer-1)
651                 console->ConsoleScrollBack = console->LineBuffer-1;
652         
653 }
654
655
656 /* Increments the command lines */
657 void CON_NewLineCommand(void) {
658         int loop;
659         char *temp;
660         
661         temp  = console->CommandLines[console->LineBuffer - 1];
662         
663         
664         for(loop = console->LineBuffer - 1; loop > 0; loop--)
665                 console->CommandLines[loop] = console->CommandLines[loop - 1];
666         
667         console->CommandLines[0] = temp;
668         
669         memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
670         if(console->TotalCommands < console->LineBuffer - 1)
671                 console->TotalCommands++;
672 }
673
674 /* Draws the command line the user is typing in to the screen */
675 /* completely rewritten by C.Wacha */
676 void DrawCommandLine() {
677         int x;
678         int commandbuffer;
679 #if 0
680         grs_font* CurrentFont;
681 #endif
682         static unsigned int LastBlinkTime = 0;  /* Last time the consoles cursor blinked */
683         static int LastCursorPos = 0;           // Last Cursor Position
684         static int Blink = 0;                   /* Is the cursor currently blinking */
685         grs_canvas *canv_save;
686         short orig_color;
687         
688         commandbuffer = console->VChars - strlen(console->Prompt)-1; // -1 to make cursor visible
689         
690 #if 0
691         CurrentFont = console->ConsoleSurface->cv_font;
692 #endif
693         
694         //Concatenate the left and right side to command
695         strcpy(console->Command, console->LCommand);
696         strncat(console->Command, console->RCommand, strlen(console->RCommand));
697         
698         //calculate display offset from current cursor position
699         if(console->Offset < console->CursorPos - commandbuffer)
700                 console->Offset = console->CursorPos - commandbuffer;
701         if(console->Offset > console->CursorPos)
702                 console->Offset = console->CursorPos;
703         
704         //first add prompt to visible part
705         strcpy(console->VCommand, console->Prompt);
706         
707         //then add the visible part of the command
708         strncat(console->VCommand, &console->Command[console->Offset], strlen(&console->Command[console->Offset]));
709         
710         //now display the result
711         
712 #if 0
713         //once again we're drawing text, so in OpenGL context we need to temporarily set up
714         //software-mode transparency.
715         if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
716                 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
717                 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
718         }
719 #endif
720         
721         canv_save = grd_curcanv;
722         gr_set_current_canvas(console->ConsoleSurface);
723         
724         //first of all restore InputBackground
725         gr_bitmap(0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->InputBackground);
726         
727         //now add the text
728         orig_color = FG_COLOR;
729         gr_string(CON_CHAR_BORDER, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->VCommand);
730         FG_COLOR = orig_color;
731         
732         //at last add the cursor
733         //check if the blink period is over
734         if(get_msecs() > LastBlinkTime) {
735                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
736                 if(Blink)
737                         Blink = 0;
738                 else
739                         Blink = 1;
740         }
741         
742         //check if cursor has moved - if yes display cursor anyway
743         if(console->CursorPos != LastCursorPos) {
744                 LastCursorPos = console->CursorPos;
745                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
746                 Blink = 1;
747         }
748         
749         if(Blink) {
750                 int prompt_width, cmd_width, h, w;
751                 
752                 gr_get_string_size(console->Prompt, &prompt_width, &h, &w);
753                 gr_get_string_size(console->LCommand + console->Offset, &cmd_width, &h, &w);
754                 x = CON_CHAR_BORDER + prompt_width + cmd_width;
755                 orig_color = FG_COLOR;
756                 if(console->InsMode)
757                         gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
758                 else
759                         gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
760                 FG_COLOR = orig_color;
761         }
762         
763         gr_set_current_canvas(canv_save);
764         
765         
766 #if 0
767         if(console->OutputScreen->flags & SDL_OPENGLBLIT) {
768                 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
769         }
770 #endif
771 }
772
773 #ifdef _MSC_VER
774 # define vsnprintf _vsnprintf
775 #endif
776
777 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
778 void CON_Out(const char *str, ...) {
779         va_list marker;
780         //keep some space free for stuff like CON_Out("blablabla %s", console->Command);
781         char temp[CON_CHARS_PER_LINE + 128];
782         char* ptemp;
783         
784         va_start(marker, str);
785         vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
786         va_end(marker);
787         
788         ptemp = temp;
789         
790         //temp now contains the complete string we want to output
791         // the only problem is that temp is maybe longer than the console
792         // width so we have to cut it into several pieces
793         
794         if(console->ConsoleLines) {
795                 while(strlen(ptemp) > console->VChars) {
796                         CON_NewLineConsole();
797                         strncpy(console->ConsoleLines[0], ptemp, console->VChars);
798                         console->ConsoleLines[0][console->VChars] = '\0';
799                         ptemp = &ptemp[console->VChars];
800                 }
801                 CON_NewLineConsole();
802                 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
803                 console->ConsoleLines[0][console->VChars] = '\0';
804                 CON_UpdateConsole();
805         }
806 }
807
808
809 #if 0
810 /* Sets the alpha level of the console, 0 turns off alpha blending */
811 void CON_Alpha(unsigned char alpha) {
812         /* store alpha as state! */
813         console->ConsoleAlpha = alpha;
814         
815         if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
816                 if(alpha == 0)
817                         SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
818                 else
819                         SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
820         }
821         
822         //      CON_UpdateConsole();
823 }
824 #endif
825
826
827 /* Adds  background image to the console, scaled to size of console*/
828 int CON_Background(grs_bitmap *image)
829 {
830         /* Free the background from the console */
831         if (image == NULL) {
832                 if (console->BackgroundImage)
833                         gr_free_bitmap(console->BackgroundImage);
834                 console->BackgroundImage = NULL;
835 #if 0
836                 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
837 #endif
838                 return 0;
839         }
840         
841         /* Load a new background */
842         if (console->BackgroundImage)
843                 gr_free_bitmap(console->BackgroundImage);
844         console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
845         gr_bitmap_scale_to(image, console->BackgroundImage);
846         
847 #if 0
848         SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
849 #endif
850         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);
851         
852         return 0;
853 }
854
855 /* Sets font info for the console */
856 void CON_Font(grs_font *font, int fg, int bg)
857 {
858         grs_canvas *canv_save;
859         
860         canv_save = grd_curcanv;
861         gr_set_current_canvas(console->ConsoleSurface);
862         gr_set_curfont(font);
863         gr_set_fontcolor(fg, bg);
864         gr_set_current_canvas(canv_save);
865 }
866
867 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
868 /* resizes the console, has to reset alot of stuff
869  * returns 1 on error */
870 int CON_Resize(int x, int y, int w, int h)
871 {
872         /* make sure that the size of the console is valid */
873         if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
874                 w = console->OutputScreen->sc_w;
875         if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
876                 h = console->OutputScreen->sc_h;
877         
878         /* resize console surface */
879         gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
880         gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
881         
882         /* Load the dirty rectangle for user input */
883         gr_free_bitmap(console->InputBackground);
884         console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
885         
886         /* Now reset some stuff dependent on the previous size */
887         console->ConsoleScrollBack = 0;
888         
889         /* Reload the background image (for the input text area) in the console */
890         if(console->BackgroundImage) {
891 #if 0
892                 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
893 #endif
894                 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);
895         }
896         
897 #if 0
898         /* restore the alpha level */
899         CON_Alpha(console->ConsoleAlpha);
900 #endif
901         return 0;
902 }
903
904 /* Transfers the console to another screen surface, and adjusts size */
905 int CON_Transfer(grs_screen *new_outputscreen, int x, int y, int w, int h)
906 {
907         console->OutputScreen = new_outputscreen;
908         
909         return(CON_Resize(x, y, w, h));
910 }
911
912 /* Sets the Prompt for console */
913 void CON_SetPrompt(char* newprompt) {
914         //check length so we can still see at least 1 char :-)
915         if(strlen(newprompt) < console->VChars)
916                 console->Prompt = d_strdup(newprompt);
917         else
918                 CON_Out("prompt too long. (max. %i chars)", console->VChars - 1);
919 }
920
921 /* Sets the key that deactivates (hides) the console. */
922 void CON_SetHideKey(int key) {
923         console->HideKey = key;
924 }
925
926 /* Executes the command entered */
927 void CON_Execute(char* command) {
928         cmd_parse(command);
929 }
930
931 void CON_TabCompletion(void) {
932         int i,j;
933         char* command;
934         
935         command = d_strdup(console->LCommand);
936         command = cmd_complete(command);
937         
938         if(!command)
939                 return; //no tab completion took place so return silently
940         
941         j = strlen(command);
942         if(j > CON_CHARS_PER_LINE - 2)
943                 j = CON_CHARS_PER_LINE-1;
944         
945         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
946         console->CursorPos = 0;
947         
948         for(i = 0; i < j; i++) {
949                 console->CursorPos++;
950                 console->LCommand[i] = command[i];
951         }
952         //add a trailing space
953         console->CursorPos++;
954         console->LCommand[j] = ' ';
955         console->LCommand[j+1] = '\0';
956 }
957
958 void Cursor_Left(void) {
959         char temp[CON_CHARS_PER_LINE];
960         
961         if(console->CursorPos > 0) {
962                 console->CursorPos--;
963                 strcpy(temp, console->RCommand);
964                 strcpy(console->RCommand, &console->LCommand[strlen(console->LCommand)-1]);
965                 strcat(console->RCommand, temp);
966                 console->LCommand[strlen(console->LCommand)-1] = '\0';
967                 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
968         }
969 }
970
971 void Cursor_Right(void) {
972         char temp[CON_CHARS_PER_LINE];
973         
974         if(console->CursorPos < strlen(console->Command)) {
975                 console->CursorPos++;
976                 strncat(console->LCommand, console->RCommand, 1);
977                 strcpy(temp, console->RCommand);
978                 strcpy(console->RCommand, &temp[1]);
979                 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
980         }
981 }
982
983 void Cursor_Home(void) {
984         char temp[CON_CHARS_PER_LINE];
985         
986         console->CursorPos = 0;
987         strcpy(temp, console->RCommand);
988         strcpy(console->RCommand, console->LCommand);
989         strncat(console->RCommand, temp, strlen(temp));
990         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
991 }
992
993 void Cursor_End(void) {
994         console->CursorPos = strlen(console->Command);
995         strncat(console->LCommand, console->RCommand, strlen(console->RCommand));
996         memset(console->RCommand, 0, CON_CHARS_PER_LINE);
997 }
998
999 void Cursor_Del(void) {
1000         char temp[CON_CHARS_PER_LINE];
1001         
1002         if(strlen(console->RCommand) > 0) {
1003                 strcpy(temp, console->RCommand);
1004                 strcpy(console->RCommand, &temp[1]);
1005         }
1006 }
1007
1008 void Cursor_BSpace(void) {
1009         if(console->CursorPos > 0) {
1010                 console->CursorPos--;
1011                 console->Offset--;
1012                 if(console->Offset < 0)
1013                         console->Offset = 0;
1014                 console->LCommand[strlen(console->LCommand)-1] = '\0';
1015         }
1016 }
1017
1018 void Cursor_Add(int event)
1019 {
1020         if(strlen(console->Command) < CON_CHARS_PER_LINE - 1)
1021         {
1022                 console->CursorPos++;
1023                 console->LCommand[strlen(console->LCommand)] = key_to_ascii(event);
1024                 console->LCommand[strlen(console->LCommand)] = '\0';
1025         }
1026 }
1027
1028 void Clear_Command(void) {
1029         console->CursorPos = 0;
1030         memset(console->VCommand, 0, CON_CHARS_PER_LINE);
1031         memset(console->Command, 0, CON_CHARS_PER_LINE);
1032         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1033         memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1034 }
1035
1036 void Clear_History(void) {
1037         int loop;
1038         
1039         for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1040                 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1041 }
1042
1043 void Command_Up(void) {
1044         if(console->CommandScrollBack < console->TotalCommands - 1) {
1045                 /* move back a line in the command strings and copy the command to the current input string */
1046                 console->CommandScrollBack++;
1047                 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1048                 console->Offset = 0;
1049                 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1050                 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1051                 CON_UpdateConsole();
1052         }
1053 }
1054
1055 void Command_Down(void) {
1056         if(console->CommandScrollBack > -1) {
1057                 /* move forward a line in the command strings and copy the command to the current input string */
1058                 console->CommandScrollBack--;
1059                 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1060                 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1061                 console->Offset = 0;
1062                 if(console->CommandScrollBack > -1)
1063                         strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1064                 console->CursorPos = strlen(console->LCommand);
1065                 CON_UpdateConsole();
1066         }
1067 }
1068
1069 /* Print a message to the console */
1070 void con_printf(int priority, char *fmt, ...)
1071 {
1072         va_list arglist;
1073         char buffer[2048];
1074
1075         if (priority <= ((int)con_threshold.value))
1076         {
1077                 va_start (arglist, fmt);
1078                 vsprintf (buffer,  fmt, arglist);
1079                 va_end (arglist);
1080
1081                 if (con_initialized)
1082                         CON_Out(buffer);
1083
1084                 if (text_console_enabled)
1085                 {
1086                         /* Produce a sanitised version and send it to the standard output */
1087                         char *p1, *p2;
1088
1089                         p1 = p2 = buffer;
1090                         do
1091                                 switch (*p1)
1092                                 {
1093                                 case CC_COLOR:
1094                                 case CC_LSPACING:
1095                                         p1++;
1096                                 case CC_UNDERLINE:
1097                                         p1++;
1098                                         break;
1099                                 default:
1100                                         *p2++ = *p1++;
1101                                 }
1102                         while (*p1);
1103                         *p2 = 0;
1104
1105                         printf("%s", buffer);
1106                 }
1107         }
1108 }