]> icculus.org git repositories - btb/d2x.git/blob - main/console.c
merged CON_console and console
[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
22 #include "console.h"
23 #include "u_mem.h"
24 #include "gr.h"
25 #include "timer.h"
26
27
28 #define FG_COLOR    grd_curcanv->cv_font_fg_color
29 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
30
31
32 /* This contains a pointer to the "topmost" console. The console that
33  * is currently taking keyboard input. */
34 static ConsoleInformation *Topmost;
35
36 /* Internals */
37 void CON_UpdateOffset(ConsoleInformation* console);
38 /*! Calls CON_Free */
39 void CON_Destroy(ConsoleInformation *console);
40 /*! Frees all the memory loaded by the console */
41 void CON_Free(ConsoleInformation *console);
42 #if 0
43 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
44  255 - opaque). Use this function also for OpenGL. */
45 void CON_Alpha(ConsoleInformation *console, unsigned char alpha);
46 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
47  Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
48 void CON_AlphaGL(SDL_Surface *s, int alpha);
49 /*! Sets a background image for the console */
50 #endif
51 int CON_Background(ConsoleInformation *console, grs_bitmap *image);
52 /*! Sets font info for the console */
53 void CON_Font(ConsoleInformation *console, grs_font *font, int fg, int bg);
54 /*! Changes current position of the console */
55 void CON_Position(ConsoleInformation *console, int x, int y);
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(ConsoleInformation* console, grs_screen* new_outputscreen, int x, int y, int w, int h);
59 /*! Give focus to a console. Make it the "topmost" console. This console will receive events
60  sent with CON_Events() */
61 void CON_Topmost(ConsoleInformation *console);
62 /*! Modify the prompt of the console */
63 void CON_SetPrompt(ConsoleInformation *console, char* newprompt);
64 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
65  ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
66 void CON_SetHideKey(ConsoleInformation *console, int key);
67 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
68 void CON_SetHideFunction(ConsoleInformation *console, void(*HideFunction)(void));
69 /*! Sets the callback function that is called after a console has been hidden */
70 void CON_Execute(ConsoleInformation *console, char* command);
71 /*! Sets the callback function that is called if a command was typed in. The function could look like this:
72  void my_command_handler(ConsoleInformation* console, char* command). @param console: the console the command
73  came from. @param command: the command string that was typed in. */
74 void CON_SetExecuteFunction(ConsoleInformation *console, void(*CmdFunction)(ConsoleInformation *console2, char* command));
75 /*! Sets the callback tabulator completion function. char* my_tabcompletion(char* command). If Tab is
76  pressed, the function gets called with the already typed in command. my_tabcompletion then checks if if can
77  complete the command or if it should display a list of all matching commands (with CON_Out()). Returns the
78  completed command or NULL if no completion was made. */
79 void CON_SetTabCompletion(ConsoleInformation *console, char*(*TabFunction)(char* command));
80 /*! Internal: Gets called when TAB was pressed */
81 void CON_TabCompletion(ConsoleInformation *console);
82 /*! Internal: makes newline (same as printf("\n") or CON_Out(console, "\n") ) */
83 void CON_NewLineConsole(ConsoleInformation *console);
84 /*! Internal: shift command history (the one you can switch with the up/down keys) */
85 void CON_NewLineCommand(ConsoleInformation *console);
86 /*! Internal: updates console after resize etc. */
87 void CON_UpdateConsole(ConsoleInformation *console);
88
89
90 /*! Internal: Default Execute callback */
91 void Default_CmdFunction(ConsoleInformation *console, char* command);
92 /*! Internal: Default TabCompletion callback */
93 char* Default_TabFunction(char* command);
94 /*! Internal: Default Hide callback */
95 void Default_HideFunction(void);
96
97 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
98 void DrawCommandLine();
99
100 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
101 void Cursor_Left(ConsoleInformation *console);
102 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
103 void Cursor_Right(ConsoleInformation *console);
104 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
105         of the line */
106 void Cursor_Home(ConsoleInformation *console);
107 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
108 void Cursor_End(ConsoleInformation *console);
109 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
110 void Cursor_Del(ConsoleInformation *console);
111 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
112 void Cursor_BSpace(ConsoleInformation *console);
113 /*! Internal: Called if you type in a character (add the char to the command) */
114 void Cursor_Add(ConsoleInformation *console, int event);
115
116 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
117 void Clear_Command(ConsoleInformation *console);
118 /*! Internal: Called if you press Ctrl-L (deletes the History) */
119 void Clear_History(ConsoleInformation *console);
120
121 /*! Internal: Called if you press UP key (switches through recent typed in commands */
122 void Command_Up(ConsoleInformation *console);
123 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
124 void Command_Down(ConsoleInformation *console);
125
126
127 /*  Takes keys from the keyboard and inputs them to the console
128  If the event was not handled (i.e. WM events or unknown ctrl-shift
129  sequences) the function returns the event for further processing. */
130 int CON_Events(int event)
131 {
132         if(Topmost == NULL)
133                 return event;
134         if(!CON_isVisible(Topmost))
135                 return event;
136         
137         if(event & KEY_CTRLED)
138         {
139                 //CTRL pressed
140                 switch(event & ~KEY_CTRLED)
141                 {
142                         case KEY_A:
143                                 Cursor_Home(Topmost);
144                                 break;
145                         case KEY_E:
146                                 Cursor_End(Topmost);
147                                 break;
148                         case KEY_C:
149                                 Clear_Command(Topmost);
150                                 break;
151                         case KEY_L:
152                                 Clear_History(Topmost);
153                                 CON_UpdateConsole(Topmost);
154                                 break;
155                         default:
156                                 return event;
157                 }
158         }
159         else if(event & KEY_ALTED)
160         {
161                 //the console does not handle ALT combinations!
162                 return event;
163         }
164         else
165         {
166                 //first of all, check if the console hide key was pressed
167                 if(event == Topmost->HideKey)
168                 {
169                         CON_Hide(Topmost);
170                         return 0;
171                 }
172                 switch (event & 0xff)
173                 {
174                         case KEY_LSHIFT:
175                         case KEY_RSHIFT:
176                                 return event;
177                         case KEY_HOME:
178                                 if(event & KEY_SHIFTED)
179                                 {
180                                         Topmost->ConsoleScrollBack = Topmost->LineBuffer-1;
181                                         CON_UpdateConsole(Topmost);
182                                 } else {
183                                         Cursor_Home(Topmost);
184                                 }
185                                 break;
186                         case KEY_END:
187                                 if(event & KEY_SHIFTED)
188                                 {
189                                         Topmost->ConsoleScrollBack = 0;
190                                         CON_UpdateConsole(Topmost);
191                                 } else {
192                                         Cursor_End(Topmost);
193                                 }
194                                 break;
195                         case KEY_PAGEUP:
196                                 Topmost->ConsoleScrollBack += CON_LINE_SCROLL;
197                                 if(Topmost->ConsoleScrollBack > Topmost->LineBuffer-1)
198                                         Topmost->ConsoleScrollBack = Topmost->LineBuffer-1;
199                                 
200                                 CON_UpdateConsole(Topmost);
201                                 break;
202                         case KEY_PAGEDOWN:
203                                 Topmost->ConsoleScrollBack -= CON_LINE_SCROLL;
204                                 if(Topmost->ConsoleScrollBack < 0)
205                                         Topmost->ConsoleScrollBack = 0;
206                                 CON_UpdateConsole(Topmost);
207                                 break;
208                         case KEY_UP:
209                                 Command_Up(Topmost);
210                                 break;
211                         case KEY_DOWN:
212                                 Command_Down(Topmost);
213                                 break;
214                         case KEY_LEFT:
215                                 Cursor_Left(Topmost);
216                                 break;
217                         case KEY_RIGHT:
218                                 Cursor_Right(Topmost);
219                                 break;
220                         case KEY_BACKSP:
221                                 Cursor_BSpace(Topmost);
222                                 break;
223                         case KEY_DELETE:
224                                 Cursor_Del(Topmost);
225                                 break;
226                         case KEY_INSERT:
227                                 Topmost->InsMode = 1-Topmost->InsMode;
228                                 break;
229                         case KEY_TAB:
230                                 CON_TabCompletion(Topmost);
231                                 break;
232                         case KEY_ENTER:
233                                 if(strlen(Topmost->Command) > 0) {
234                                         CON_NewLineCommand(Topmost);
235                                         
236                                         // copy the input into the past commands strings
237                                         strcpy(Topmost->CommandLines[0], Topmost->Command);
238                                         
239                                         // display the command including the prompt
240                                         CON_Out(Topmost, "%s%s", Topmost->Prompt, Topmost->Command);
241                                         CON_UpdateConsole(Topmost);
242                                         
243                                         CON_Execute(Topmost, Topmost->Command);
244                                         //printf("Command: %s\n", Topmost->Command);
245                                         
246                                         Clear_Command(Topmost);
247                                         Topmost->CommandScrollBack = -1;
248                                 }
249                                 break;
250                         case KEY_LAPOSTRO:
251                                 //deactivate Console
252                                 CON_Hide(Topmost);
253                                 return 0;
254                         default:
255                                 if (key_to_ascii(event) == 255)
256                                         break;
257                                 if(Topmost->InsMode)
258                                         Cursor_Add(Topmost, event);
259                                 else {
260                                         Cursor_Add(Topmost, event);
261                                         Cursor_Del(Topmost);
262                                 }
263                 }
264         }
265         return 0;
266 }
267
268 #if 0
269 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
270  * specified value.  Preconditions: the surface in question is RGBA.
271  * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
272 void CON_AlphaGL(SDL_Surface *s, int alpha) {
273         Uint8 val;
274         int x, y, w, h;
275         Uint32 pixel;
276         Uint8 r, g, b, a;
277         SDL_PixelFormat *format;
278         static char errorPrinted = 0;
279         
280         
281         /* debugging assertions -- these slow you down, but hey, crashing sucks */
282         if(!s) {
283                 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
284                 return;
285         }
286         
287         /* clamp alpha value to 0...255 */
288         if(alpha < SDL_ALPHA_TRANSPARENT)
289                 val = SDL_ALPHA_TRANSPARENT;
290         else if(alpha > SDL_ALPHA_OPAQUE)
291                 val = SDL_ALPHA_OPAQUE;
292         else
293                 val = alpha;
294         
295         /* loop over alpha channels of each pixel, setting them appropriately. */
296         w = s->w;
297         h = s->h;
298         format = s->format;
299         switch (format->BytesPerPixel) {
300                 case 2:
301                         /* 16-bit surfaces don't seem to support alpha channels. */
302                         if(!errorPrinted) {
303                                 errorPrinted = 1;
304                                 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
305                         }
306                         break;
307                 case 4: {
308                         /* we can do this very quickly in 32-bit mode.  24-bit is more
309                          * difficult.  And since 24-bit mode is reall the same as 32-bit,
310                          * so it usually ends up taking this route too.  Win!  Unroll loop
311                          * and use pointer arithmetic for extra speed. */
312                         int numpixels = h * (w << 2);
313                         Uint8 *pix = (Uint8 *) (s->pixels);
314                         Uint8 *last = pix + numpixels;
315                         Uint8 *pixel;
316                         if((numpixels & 0x7) == 0)
317                                 for(pixel = pix + 3; pixel < last; pixel += 32)
318                                         *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
319                         else
320                                 for(pixel = pix + 3; pixel < last; pixel += 4)
321                                         *pixel = val;
322                         break;
323                 }
324                 default:
325                         /* we have no choice but to do this slowly.  <sigh> */
326                         for(y = 0; y < h; ++y)
327                                 for(x = 0; x < w; ++x) {
328                                         char print = 0;
329                                         /* Lock the surface for direct access to the pixels */
330                                         if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
331                                                 PRINT_ERROR("Can't lock surface: ");
332                                                 fprintf(stderr, "%s\n", SDL_GetError());
333                                                 return;
334                                         }
335                                         pixel = DT_GetPixel(s, x, y);
336                                         if(x == 0 && y == 0)
337                                                 print = 1;
338                                         SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
339                                         pixel = SDL_MapRGBA(format, r, g, b, val);
340                                         SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
341                                         DT_PutPixel(s, x, y, pixel);
342                                         
343                                         /* unlock surface again */
344                                         if(SDL_MUSTLOCK(s))
345                                                 SDL_UnlockSurface(s);
346                                 }
347                         break;
348         }
349 }
350 #endif
351
352
353 /* Updates the console buffer */
354 void CON_UpdateConsole(ConsoleInformation *console) {
355         int loop;
356         int loop2;
357         int Screenlines;
358         grs_canvas *canv_save;
359         short orig_color;
360         
361         if(!console)
362                 return;
363         
364         /* Due to the Blits, the update is not very fast: So only update if it's worth it */
365         if(!CON_isVisible(console))
366                 return;
367         
368         Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
369         
370         canv_save = grd_curcanv;
371         gr_set_current_canvas(console->ConsoleSurface);
372         
373 #if 0
374         SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
375 #else
376         //gr_rect(0,0,
377 #endif
378         
379 #if 0
380         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
381                 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
382 #endif
383         
384         /* draw the background image if there is one */
385         if(console->BackgroundImage)
386                 gr_bitmap(0, 0, console->BackgroundImage);
387         
388         /* Draw the text from the back buffers, calculate in the scrollback from the user
389          * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
390          * for the font, and then clear it when we're done.
391          */
392 #if 0
393         if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
394                 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
395                 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
396         }
397 #endif
398         
399         //now draw text from last but second line to top
400         for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
401                 if(console->ConsoleScrollBack != 0 && loop == 0)
402                         for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
403                         {
404                                 orig_color = FG_COLOR;
405                                 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);
406                                 FG_COLOR = orig_color;
407                         }
408                 else
409                 {
410                         orig_color = FG_COLOR;
411                         gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
412                         FG_COLOR = orig_color;
413                 }
414         }
415         
416         gr_set_current_canvas(canv_save);
417         
418 #if 0
419         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
420                 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
421 #endif
422 }
423
424 void CON_UpdateOffset(ConsoleInformation* console) {
425         if(!console)
426                 return;
427         
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(ConsoleInformation *console) {
451         grs_canvas *canv_save;
452         grs_bitmap *clip;
453         
454         if(!console)
455                 return;
456         
457         /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
458         if(console->Visible == CON_CLOSED)
459                 return;
460         
461         /* Update the scrolling offset */
462         CON_UpdateOffset(console);
463         
464         /* Update the command line since it has a blinking cursor */
465         DrawCommandLine();
466         
467 #if 0
468         /* before drawing, make sure the alpha channel of the console surface is set
469          * properly.  (sigh) I wish we didn't have to do this every frame... */
470         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
471                 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
472 #endif
473         
474         canv_save = grd_curcanv;
475         gr_set_current_canvas(&console->OutputScreen->sc_canvas);
476         
477         clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
478         
479         gr_bitmap(console->DispX, console->DispY, clip);
480         gr_free_sub_bitmap(clip);
481         
482 #if 0
483         if(console->OutputScreen->flags & SDL_OPENGLBLIT)
484                 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
485 #endif
486         
487         gr_set_current_canvas(canv_save);
488 }
489
490
491 /* Initializes the console */
492 ConsoleInformation *CON_Init(grs_font *Font, grs_screen *DisplayScreen, int lines, int x, int y, int w, int h)
493 {
494         int loop;
495         ConsoleInformation *newinfo;
496         
497         
498         /* Create a new console struct and init it. */
499         if((newinfo = (ConsoleInformation *) d_malloc(sizeof(ConsoleInformation))) == NULL) {
500                 //PRINT_ERROR("Could not allocate the space for a new console info struct.\n");
501                 return NULL;
502         }
503         newinfo->Visible = CON_CLOSED;
504         newinfo->RaiseOffset = 0;
505         newinfo->ConsoleLines = NULL;
506         newinfo->CommandLines = NULL;
507         newinfo->TotalConsoleLines = 0;
508         newinfo->ConsoleScrollBack = 0;
509         newinfo->TotalCommands = 0;
510         newinfo->BackgroundImage = NULL;
511 #if 0
512         newinfo->ConsoleAlpha = SDL_ALPHA_OPAQUE;
513 #endif
514         newinfo->Offset = 0;
515         newinfo->InsMode = 1;
516         newinfo->CursorPos = 0;
517         newinfo->CommandScrollBack = 0;
518         newinfo->OutputScreen = DisplayScreen;
519         newinfo->Prompt = CON_DEFAULT_PROMPT;
520         newinfo->HideKey = CON_DEFAULT_HIDEKEY;
521         
522         CON_SetExecuteFunction(newinfo, Default_CmdFunction);
523         CON_SetTabCompletion(newinfo, Default_TabFunction);
524         CON_SetHideFunction(newinfo, Default_HideFunction);
525         
526         /* make sure that the size of the console is valid */
527         if(w > newinfo->OutputScreen->sc_w || w < Font->ft_w * 32)
528                 w = newinfo->OutputScreen->sc_w;
529         if(h > newinfo->OutputScreen->sc_h || h < Font->ft_h)
530                 h = newinfo->OutputScreen->sc_h;
531         if(x < 0 || x > newinfo->OutputScreen->sc_w - w)
532                 newinfo->DispX = 0;
533         else
534                 newinfo->DispX = x;
535         if(y < 0 || y > newinfo->OutputScreen->sc_h - h)
536                 newinfo->DispY = 0;
537         else
538                 newinfo->DispY = y;
539         
540         /* load the console surface */
541         newinfo->ConsoleSurface = gr_create_canvas(w, h);
542         
543         /* Load the consoles font */
544         {
545                 grs_canvas *canv_save;
546                 
547                 canv_save = grd_curcanv;
548                 gr_set_current_canvas(newinfo->ConsoleSurface);
549                 gr_set_curfont(Font);
550                 gr_set_fontcolor(gr_getcolor(63,63,63), -1);
551                 gr_set_current_canvas(canv_save);
552         }
553         
554         
555         /* Load the dirty rectangle for user input */
556         newinfo->InputBackground = gr_create_bitmap(w, newinfo->ConsoleSurface->cv_font->ft_h);
557 #if 0
558         SDL_FillRect(newinfo->InputBackground, NULL, SDL_MapRGBA(newinfo->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
559 #endif
560         
561         /* calculate the number of visible characters in the command line */
562         newinfo->VChars = (w - CON_CHAR_BORDER) / newinfo->ConsoleSurface->cv_font->ft_w;
563         if(newinfo->VChars > CON_CHARS_PER_LINE)
564                 newinfo->VChars = CON_CHARS_PER_LINE;
565         
566         /* We would like to have a minumum # of lines to guarentee we don't create a memory error */
567         if(h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h) > lines)
568                 newinfo->LineBuffer = h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h);
569         else
570                 newinfo->LineBuffer = lines;
571         
572         
573         newinfo->ConsoleLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
574         newinfo->CommandLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
575         for(loop = 0; loop <= newinfo->LineBuffer - 1; loop++) {
576                 newinfo->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
577                 newinfo->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
578         }
579         memset(newinfo->Command, 0, CON_CHARS_PER_LINE);
580         memset(newinfo->LCommand, 0, CON_CHARS_PER_LINE);
581         memset(newinfo->RCommand, 0, CON_CHARS_PER_LINE);
582         memset(newinfo->VCommand, 0, CON_CHARS_PER_LINE);
583         
584         
585         CON_Out(newinfo, "Console initialised.");
586         CON_NewLineConsole(newinfo);
587         //CON_ListCommands(newinfo);
588         
589         return newinfo;
590 }
591
592 /* Makes the console visible */
593 void CON_Show(ConsoleInformation *console) {
594         if(console) {
595                 console->Visible = CON_OPENING;
596                 CON_UpdateConsole(console);
597         }
598 }
599
600 /* Hides the console (make it invisible) */
601 void CON_Hide(ConsoleInformation *console) {
602         if(console)
603                 console->Visible = CON_CLOSING;
604         console->HideFunction();
605 }
606
607 /* tells wether the console is visible or not */
608 int CON_isVisible(ConsoleInformation *console) {
609         if(!console)
610                 return CON_CLOSED;
611         return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
612 }
613
614 /* Frees all the memory loaded by the console */
615 void CON_Destroy(ConsoleInformation *console) {
616         CON_Free(console);
617 }
618
619 /* Frees all the memory loaded by the console */
620 void CON_Free(ConsoleInformation *console) {
621         int i;
622         
623         if(!console)
624                 return;
625         
626         //CON_DestroyCommands();
627         for(i = 0; i <= console->LineBuffer - 1; i++) {
628                 d_free(console->ConsoleLines[i]);
629                 d_free(console->CommandLines[i]);
630         }
631         d_free(console->ConsoleLines);
632         d_free(console->CommandLines);
633         
634         console->ConsoleLines = NULL;
635         console->CommandLines = NULL;
636         
637         gr_free_canvas(console->ConsoleSurface);
638         console->ConsoleSurface = NULL;
639         
640         if (console->BackgroundImage)
641                 gr_free_bitmap(console->BackgroundImage);
642         console->BackgroundImage = NULL;
643         
644         gr_free_bitmap(console->InputBackground);
645         console->InputBackground = NULL;
646         
647         d_free(console);
648 }
649
650
651 /* Increments the console lines */
652 void CON_NewLineConsole(ConsoleInformation *console) {
653         int loop;
654         char* temp;
655         
656         if(!console)
657                 return;
658         
659         temp = console->ConsoleLines[console->LineBuffer - 1];
660         
661         for(loop = console->LineBuffer - 1; loop > 0; loop--)
662                 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
663         
664         console->ConsoleLines[0] = temp;
665         
666         memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
667         if(console->TotalConsoleLines < console->LineBuffer - 1)
668                 console->TotalConsoleLines++;
669         
670         //Now adjust the ConsoleScrollBack
671         //dont scroll if not at bottom
672         if(console->ConsoleScrollBack != 0)
673                 console->ConsoleScrollBack++;
674         //boundaries
675         if(console->ConsoleScrollBack > console->LineBuffer-1)
676                 console->ConsoleScrollBack = console->LineBuffer-1;
677         
678 }
679
680
681 /* Increments the command lines */
682 void CON_NewLineCommand(ConsoleInformation *console) {
683         int loop;
684         char *temp;
685         
686         if(!console)
687                 return;
688         
689         temp  = console->CommandLines[console->LineBuffer - 1];
690         
691         
692         for(loop = console->LineBuffer - 1; loop > 0; loop--)
693                 console->CommandLines[loop] = console->CommandLines[loop - 1];
694         
695         console->CommandLines[0] = temp;
696         
697         memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
698         if(console->TotalCommands < console->LineBuffer - 1)
699                 console->TotalCommands++;
700 }
701
702 /* Draws the command line the user is typing in to the screen */
703 /* completely rewritten by C.Wacha */
704 void DrawCommandLine() {
705         int x;
706         int commandbuffer;
707 #if 0
708         grs_font* CurrentFont;
709 #endif
710         static unsigned int LastBlinkTime = 0;  /* Last time the consoles cursor blinked */
711         static int LastCursorPos = 0;           // Last Cursor Position
712         static int Blink = 0;                   /* Is the cursor currently blinking */
713         grs_canvas *canv_save;
714         short orig_color;
715         
716         if(!Topmost)
717                 return;
718         
719         commandbuffer = Topmost->VChars - strlen(Topmost->Prompt)-1; // -1 to make cursor visible
720         
721 #if 0
722         CurrentFont = Topmost->ConsoleSurface->cv_font;
723 #endif
724         
725         //Concatenate the left and right side to command
726         strcpy(Topmost->Command, Topmost->LCommand);
727         strncat(Topmost->Command, Topmost->RCommand, strlen(Topmost->RCommand));
728         
729         //calculate display offset from current cursor position
730         if(Topmost->Offset < Topmost->CursorPos - commandbuffer)
731                 Topmost->Offset = Topmost->CursorPos - commandbuffer;
732         if(Topmost->Offset > Topmost->CursorPos)
733                 Topmost->Offset = Topmost->CursorPos;
734         
735         //first add prompt to visible part
736         strcpy(Topmost->VCommand, Topmost->Prompt);
737         
738         //then add the visible part of the command
739         strncat(Topmost->VCommand, &Topmost->Command[Topmost->Offset], strlen(&Topmost->Command[Topmost->Offset]));
740         
741         //now display the result
742         
743 #if 0
744         //once again we're drawing text, so in OpenGL context we need to temporarily set up
745         //software-mode transparency.
746         if(Topmost->OutputScreen->flags & SDL_OPENGLBLIT) {
747                 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
748                 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
749         }
750 #endif
751         
752         canv_save = grd_curcanv;
753         gr_set_current_canvas(Topmost->ConsoleSurface);
754         
755         //first of all restore InputBackground
756         gr_bitmap(0, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->InputBackground);
757         
758         //now add the text
759         orig_color = FG_COLOR;
760         gr_string(CON_CHAR_BORDER, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->VCommand);
761         FG_COLOR = orig_color;
762         
763         //at last add the cursor
764         //check if the blink period is over
765         if(get_msecs() > LastBlinkTime) {
766                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
767                 if(Blink)
768                         Blink = 0;
769                 else
770                         Blink = 1;
771         }
772         
773         //check if cursor has moved - if yes display cursor anyway
774         if(Topmost->CursorPos != LastCursorPos) {
775                 LastCursorPos = Topmost->CursorPos;
776                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
777                 Blink = 1;
778         }
779         
780         if(Blink) {
781                 int prompt_width, cmd_width, h, w;
782                 
783                 gr_get_string_size(Topmost->Prompt, &prompt_width, &h, &w);
784                 gr_get_string_size(Topmost->LCommand + Topmost->Offset, &cmd_width, &h, &w);
785                 x = CON_CHAR_BORDER + prompt_width + cmd_width;
786                 orig_color = FG_COLOR;
787                 if(Topmost->InsMode)
788                         gr_string(x, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
789                 else
790                         gr_string(x, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
791                 FG_COLOR = orig_color;
792         }
793         
794         gr_set_current_canvas(canv_save);
795         
796         
797 #if 0
798         if(Topmost->OutputScreen->flags & SDL_OPENGLBLIT) {
799                 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
800         }
801 #endif
802 }
803
804 #ifdef _MSC_VER
805 # define vsnprintf _vsnprintf
806 #endif
807
808 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
809 void CON_Out(ConsoleInformation *console, const char *str, ...) {
810         va_list marker;
811         //keep some space free for stuff like CON_Out(console, "blablabla %s", console->Command);
812         char temp[CON_CHARS_PER_LINE + 128];
813         char* ptemp;
814         
815         if(!console)
816                 return;
817         
818         va_start(marker, str);
819         vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
820         va_end(marker);
821         
822         ptemp = temp;
823         
824         //temp now contains the complete string we want to output
825         // the only problem is that temp is maybe longer than the console
826         // width so we have to cut it into several pieces
827         
828         if(console->ConsoleLines) {
829                 while(strlen(ptemp) > console->VChars) {
830                         CON_NewLineConsole(console);
831                         strncpy(console->ConsoleLines[0], ptemp, console->VChars);
832                         console->ConsoleLines[0][console->VChars] = '\0';
833                         ptemp = &ptemp[console->VChars];
834                 }
835                 CON_NewLineConsole(console);
836                 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
837                 console->ConsoleLines[0][console->VChars] = '\0';
838                 CON_UpdateConsole(console);
839         }
840         
841         /* And print to stdout */
842         //printf("%s\n", temp);
843 }
844
845
846 #if 0
847 /* Sets the alpha level of the console, 0 turns off alpha blending */
848 void CON_Alpha(ConsoleInformation *console, unsigned char alpha) {
849         if(!console)
850                 return;
851         
852         /* store alpha as state! */
853         console->ConsoleAlpha = alpha;
854         
855         if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
856                 if(alpha == 0)
857                         SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
858                 else
859                         SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
860         }
861         
862         //      CON_UpdateConsole(console);
863 }
864 #endif
865
866
867 /* Adds  background image to the console, scaled to size of console*/
868 int CON_Background(ConsoleInformation *console, grs_bitmap *image)
869 {
870         if(!console)
871                 return 1;
872         
873         /* Free the background from the console */
874         if (image == NULL) {
875                 if (console->BackgroundImage)
876                         gr_free_bitmap(console->BackgroundImage);
877                 console->BackgroundImage = NULL;
878 #if 0
879                 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
880 #endif
881                 return 0;
882         }
883         
884         /* Load a new background */
885         if (console->BackgroundImage)
886                 gr_free_bitmap(console->BackgroundImage);
887         console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
888         gr_bitmap_scale_to(image, console->BackgroundImage);
889         
890 #if 0
891         SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
892 #endif
893         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);
894         
895         return 0;
896 }
897
898 /* Sets font info for the console */
899 void CON_Font(ConsoleInformation *console, grs_font *font, int fg, int bg)
900 {
901         grs_canvas *canv_save;
902         
903         canv_save = grd_curcanv;
904         gr_set_current_canvas(console->ConsoleSurface);
905         gr_set_curfont(font);
906         gr_set_fontcolor(fg, bg);
907         gr_set_current_canvas(canv_save);
908 }
909
910 /* takes a new x and y of the top left of the console window */
911 void CON_Position(ConsoleInformation *console, int x, int y) {
912         if(!console)
913                 return;
914         
915         if(x < 0 || x > console->OutputScreen->sc_w - console->ConsoleSurface->cv_w)
916                 console->DispX = 0;
917         else
918                 console->DispX = x;
919         
920         if(y < 0 || y > console->OutputScreen->sc_h - console->ConsoleSurface->cv_h)
921                 console->DispY = 0;
922         else
923                 console->DispY = y;
924 }
925
926 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
927 /* resizes the console, has to reset alot of stuff
928  * returns 1 on error */
929 int CON_Resize(ConsoleInformation *console, int x, int y, int w, int h)
930 {
931         if(!console)
932                 return 1;
933         
934         /* make sure that the size of the console is valid */
935         if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
936                 w = console->OutputScreen->sc_w;
937         if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
938                 h = console->OutputScreen->sc_h;
939         if(x < 0 || x > console->OutputScreen->sc_w - w)
940                 console->DispX = 0;
941         else
942                 console->DispX = x;
943         if(y < 0 || y > console->OutputScreen->sc_h - h)
944                 console->DispY = 0;
945         else
946                 console->DispY = y;
947         
948         /* resize console surface */
949         gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
950         gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
951         
952         /* Load the dirty rectangle for user input */
953         gr_free_bitmap(console->InputBackground);
954         console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
955         
956         /* Now reset some stuff dependent on the previous size */
957         console->ConsoleScrollBack = 0;
958         
959         /* Reload the background image (for the input text area) in the console */
960         if(console->BackgroundImage) {
961 #if 0
962                 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
963 #endif
964                 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);
965         }
966         
967 #if 0
968         /* restore the alpha level */
969         CON_Alpha(console, console->ConsoleAlpha);
970 #endif
971         return 0;
972 }
973
974 /* Transfers the console to another screen surface, and adjusts size */
975 int CON_Transfer(ConsoleInformation *console, grs_screen *new_outputscreen, int x, int y, int w, int h)
976 {
977         if(!console)
978                 return 1;
979         
980         console->OutputScreen = new_outputscreen;
981         
982         return(CON_Resize(console, x, y, w, h));
983 }
984
985 /* Sets the topmost console for input */
986 void CON_Topmost(ConsoleInformation *console) {
987         grs_canvas *canv_save;
988         short orig_color;
989         
990         if(!console)
991                 return;
992         
993         // Make sure the blinking cursor is gone
994         if(Topmost) {
995                 canv_save = grd_curcanv;
996                 gr_set_current_canvas(Topmost->ConsoleSurface);
997                 
998                 gr_bitmap(0, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->InputBackground);
999                 orig_color = FG_COLOR;
1000                 gr_string(CON_CHAR_BORDER, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->VCommand);
1001                 FG_COLOR = orig_color;
1002                 
1003                 gr_set_current_canvas(canv_save);
1004         }
1005         Topmost = console;
1006 }
1007
1008 /* Sets the Prompt for console */
1009 void CON_SetPrompt(ConsoleInformation *console, char* newprompt) {
1010         if(!console)
1011                 return;
1012         
1013         //check length so we can still see at least 1 char :-)
1014         if(strlen(newprompt) < console->VChars)
1015                 console->Prompt = d_strdup(newprompt);
1016         else
1017                 CON_Out(console, "prompt too long. (max. %i chars)", console->VChars - 1);
1018 }
1019
1020 /* Sets the key that deactivates (hides) the console. */
1021 void CON_SetHideKey(ConsoleInformation *console, int key) {
1022         if(console)
1023                 console->HideKey = key;
1024 }
1025
1026 void CON_SetHideFunction(ConsoleInformation *console, void(*HideFunction)(void)) {
1027         if(console)
1028                 console->HideFunction = HideFunction;
1029 }
1030
1031 void Default_HideFunction(void) {
1032 }
1033
1034 /* Executes the command entered */
1035 void CON_Execute(ConsoleInformation *console, char* command) {
1036         if(console)
1037                 console->CmdFunction(console, command);
1038 }
1039
1040 void CON_SetExecuteFunction(ConsoleInformation *console, void(*CmdFunction)(ConsoleInformation *console2, char* command)) {
1041         if(console)
1042                 console->CmdFunction = CmdFunction;
1043 }
1044
1045 void Default_CmdFunction(ConsoleInformation *console, char* command) {
1046         CON_Out(console, "     No CommandFunction registered");
1047         CON_Out(console, "     use 'CON_SetExecuteFunction' to register one");
1048         CON_Out(console, " ");
1049         CON_Out(console, "Unknown Command \"%s\"", command);
1050 }
1051
1052 void CON_SetTabCompletion(ConsoleInformation *console, char*(*TabFunction)(char* command)) {
1053         if(console)
1054                 console->TabFunction = TabFunction;
1055 }
1056
1057 void CON_TabCompletion(ConsoleInformation *console) {
1058         int i,j;
1059         char* command;
1060         
1061         if(!console)
1062                 return;
1063         
1064         command = d_strdup(console->LCommand);
1065         command = console->TabFunction(command);
1066         
1067         if(!command)
1068                 return; //no tab completion took place so return silently
1069         
1070         j = strlen(command);
1071         if(j > CON_CHARS_PER_LINE - 2)
1072                 j = CON_CHARS_PER_LINE-1;
1073         
1074         memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1075         console->CursorPos = 0;
1076         
1077         for(i = 0; i < j; i++) {
1078                 console->CursorPos++;
1079                 console->LCommand[i] = command[i];
1080         }
1081         //add a trailing space
1082         console->CursorPos++;
1083         console->LCommand[j] = ' ';
1084         console->LCommand[j+1] = '\0';
1085 }
1086
1087 char* Default_TabFunction(char* command) {
1088         CON_Out(Topmost, "     No TabFunction registered");
1089         CON_Out(Topmost, "     use 'CON_SetTabCompletion' to register one");
1090         CON_Out(Topmost, " ");
1091         return NULL;
1092 }
1093
1094 void Cursor_Left(ConsoleInformation *console) {
1095         char temp[CON_CHARS_PER_LINE];
1096         
1097         if(Topmost->CursorPos > 0) {
1098                 Topmost->CursorPos--;
1099                 strcpy(temp, Topmost->RCommand);
1100                 strcpy(Topmost->RCommand, &Topmost->LCommand[strlen(Topmost->LCommand)-1]);
1101                 strcat(Topmost->RCommand, temp);
1102                 Topmost->LCommand[strlen(Topmost->LCommand)-1] = '\0';
1103                 //CON_Out(Topmost, "L:%s, R:%s", Topmost->LCommand, Topmost->RCommand);
1104         }
1105 }
1106
1107 void Cursor_Right(ConsoleInformation *console) {
1108         char temp[CON_CHARS_PER_LINE];
1109         
1110         if(Topmost->CursorPos < strlen(Topmost->Command)) {
1111                 Topmost->CursorPos++;
1112                 strncat(Topmost->LCommand, Topmost->RCommand, 1);
1113                 strcpy(temp, Topmost->RCommand);
1114                 strcpy(Topmost->RCommand, &temp[1]);
1115                 //CON_Out(Topmost, "L:%s, R:%s", Topmost->LCommand, Topmost->RCommand);
1116         }
1117 }
1118
1119 void Cursor_Home(ConsoleInformation *console) {
1120         char temp[CON_CHARS_PER_LINE];
1121         
1122         Topmost->CursorPos = 0;
1123         strcpy(temp, Topmost->RCommand);
1124         strcpy(Topmost->RCommand, Topmost->LCommand);
1125         strncat(Topmost->RCommand, temp, strlen(temp));
1126         memset(Topmost->LCommand, 0, CON_CHARS_PER_LINE);
1127 }
1128
1129 void Cursor_End(ConsoleInformation *console) {
1130         Topmost->CursorPos = strlen(Topmost->Command);
1131         strncat(Topmost->LCommand, Topmost->RCommand, strlen(Topmost->RCommand));
1132         memset(Topmost->RCommand, 0, CON_CHARS_PER_LINE);
1133 }
1134
1135 void Cursor_Del(ConsoleInformation *console) {
1136         char temp[CON_CHARS_PER_LINE];
1137         
1138         if(strlen(Topmost->RCommand) > 0) {
1139                 strcpy(temp, Topmost->RCommand);
1140                 strcpy(Topmost->RCommand, &temp[1]);
1141         }
1142 }
1143
1144 void Cursor_BSpace(ConsoleInformation *console) {
1145         if(Topmost->CursorPos > 0) {
1146                 Topmost->CursorPos--;
1147                 Topmost->Offset--;
1148                 if(Topmost->Offset < 0)
1149                         Topmost->Offset = 0;
1150                 Topmost->LCommand[strlen(Topmost->LCommand)-1] = '\0';
1151         }
1152 }
1153
1154 void Cursor_Add(ConsoleInformation *console, int event)
1155 {
1156         if(strlen(Topmost->Command) < CON_CHARS_PER_LINE - 1)
1157         {
1158                 Topmost->CursorPos++;
1159                 Topmost->LCommand[strlen(Topmost->LCommand)] = key_to_ascii(event);
1160                 Topmost->LCommand[strlen(Topmost->LCommand)] = '\0';
1161         }
1162 }
1163
1164 void Clear_Command(ConsoleInformation *console) {
1165         Topmost->CursorPos = 0;
1166         memset(Topmost->VCommand, 0, CON_CHARS_PER_LINE);
1167         memset(Topmost->Command, 0, CON_CHARS_PER_LINE);
1168         memset(Topmost->LCommand, 0, CON_CHARS_PER_LINE);
1169         memset(Topmost->RCommand, 0, CON_CHARS_PER_LINE);
1170 }
1171
1172 void Clear_History(ConsoleInformation *console) {
1173         int loop;
1174         
1175         for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1176                 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1177 }
1178
1179 void Command_Up(ConsoleInformation *console) {
1180         if(console->CommandScrollBack < console->TotalCommands - 1) {
1181                 /* move back a line in the command strings and copy the command to the current input string */
1182                 console->CommandScrollBack++;
1183                 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1184                 console->Offset = 0;
1185                 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1186                 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1187                 CON_UpdateConsole(console);
1188         }
1189 }
1190
1191 void Command_Down(ConsoleInformation *console) {
1192         if(console->CommandScrollBack > -1) {
1193                 /* move forward a line in the command strings and copy the command to the current input string */
1194                 console->CommandScrollBack--;
1195                 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1196                 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1197                 console->Offset = 0;
1198                 if(console->CommandScrollBack > -1)
1199                         strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1200                 console->CursorPos = strlen(console->LCommand);
1201                 CON_UpdateConsole(console);
1202         }
1203 }
1204
1205 #include <stdio.h>
1206 #include <stdlib.h>
1207 #include <stdarg.h>
1208 #include <string.h>
1209 #ifndef _WIN32_WCE
1210 #include <fcntl.h>
1211 #endif
1212 #include <ctype.h>
1213
1214 #include "pstypes.h"
1215 #include "u_mem.h"
1216 #include "error.h"
1217 #include "console.h"
1218 #include "cmd.h"
1219 #include "cvar.h"
1220 #include "gr.h"
1221 #include "gamefont.h"
1222 #include "pcx.h"
1223 #include "cfile.h"
1224
1225 #ifndef __MSDOS__
1226 int text_console_enabled = 1;
1227 #else
1228 int isvga();
1229 #define text_console_enabled (!isvga())
1230 #endif
1231
1232 int Console_open = 0;
1233
1234 /* Console specific cvars */
1235 /* How discriminating we are about which messages are displayed */
1236 cvar_t con_threshold = {"con_threshold", "0",};
1237
1238 /* Private console stuff */
1239 #define CON_NUM_LINES 40
1240 #if 0
1241 #define CON_LINE_LEN 40
1242 static char con_display[40][40];
1243 static int  con_line; /* Current display line */
1244 #endif
1245
1246 #ifdef CONSOLE
1247 static int con_initialized;
1248
1249 ConsoleInformation *Console;
1250
1251 void con_parse(ConsoleInformation *console, char *command);
1252 void con_hide();
1253
1254
1255 /* Free the console */
1256 void con_free(void)
1257 {
1258         if (con_initialized)
1259                 CON_Free(Console);
1260         con_initialized = 0;
1261 }
1262 #endif
1263
1264
1265 /* Initialise the console */
1266 void con_init(void)
1267 {
1268         grs_screen fake_screen;
1269         grs_font   fake_font;
1270
1271         fake_screen.sc_w = 320;
1272         fake_screen.sc_h = 200;
1273         fake_font.ft_w = 5;
1274         fake_font.ft_h = 5;
1275
1276         Console = CON_Init(&fake_font, &fake_screen, CON_NUM_LINES, 0, 0, 320, 200);
1277
1278         CON_SetExecuteFunction(Console, con_parse);
1279         CON_SetHideFunction(Console, con_hide);
1280
1281
1282         cmd_init();
1283
1284         /* Initialise the cvars */
1285         cvar_registervariable (&con_threshold);
1286
1287         con_initialized = 1;
1288
1289         atexit(con_free);
1290 }
1291
1292 #ifdef CONSOLE
1293
1294 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
1295 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
1296 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
1297
1298 void con_background(char *filename)
1299 {
1300         int pcx_error;
1301         grs_bitmap bmp;
1302         ubyte pal[256*3];
1303
1304         gr_init_bitmap_data(&bmp);
1305         pcx_error = pcx_read_bitmap(filename, &bmp, BM_LINEAR, pal);
1306         Assert(pcx_error == PCX_ERROR_NONE);
1307         gr_remap_bitmap_good(&bmp, pal, -1, -1);
1308         CON_Background(Console, &bmp);
1309         gr_free_bitmap_data(&bmp);
1310 }
1311
1312
1313 void con_init_gfx(void)
1314 {
1315         CON_Font(Console, SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1316         CON_Transfer(Console, grd_curscreen, 0, 0, SWIDTH, SHEIGHT / 2);
1317
1318         con_background(CON_BG);
1319 }
1320 #endif
1321
1322
1323 void con_resize(void)
1324 {
1325 #ifdef CONSOLE
1326         CON_Font(Console, SMALL_FONT, gr_getcolor(63, 63, 63), -1);
1327         CON_Resize(Console, 0, 0, SWIDTH, SHEIGHT / 2);
1328         con_background(CON_BG);
1329 #endif
1330 }
1331
1332 /* Print a message to the console */
1333 void con_printf(int priority, char *fmt, ...)
1334 {
1335         va_list arglist;
1336         char buffer[2048];
1337
1338         if (priority <= ((int)con_threshold.value))
1339         {
1340                 va_start (arglist, fmt);
1341                 vsprintf (buffer,  fmt, arglist);
1342                 va_end (arglist);
1343
1344 #ifdef CONSOLE
1345                 if (con_initialized)
1346                         CON_Out(Console, buffer);
1347 #endif
1348
1349 /*              for (i=0; i<l; i+=CON_LINE_LEN,con_line++)
1350                 {
1351                         memcpy(con_display, &buffer[i], min(80, l-i));
1352                 }*/
1353
1354                 if (text_console_enabled)
1355                 {
1356                         /* Produce a sanitised version and send it to the standard output */
1357                         char *p1, *p2;
1358
1359                         p1 = p2 = buffer;
1360                         do
1361                                 switch (*p1)
1362                                 {
1363                                 case CC_COLOR:
1364                                 case CC_LSPACING:
1365                                         p1++;
1366                                 case CC_UNDERLINE:
1367                                         p1++;
1368                                         break;
1369                                 default:
1370                                         *p2++ = *p1++;
1371                                 }
1372                         while (*p1);
1373                         *p2 = 0;
1374
1375                         printf("%s", buffer);
1376                 }
1377         }
1378 }
1379
1380 /* Check for new console input. If it's there, use it */
1381 void con_update(void)
1382 {
1383 #if 0
1384         char buffer[CMD_MAX_LENGTH], *t;
1385
1386         /* Check for new input */
1387         t = fgets(buffer, sizeof(buffer), stdin);
1388         if (t == NULL) return;
1389
1390         cmd_parse(buffer);
1391 #endif
1392         con_draw();
1393 }
1394
1395
1396 int con_events(int key)
1397 {
1398 #ifdef CONSOLE
1399         return CON_Events(key);
1400 #else
1401         return key;
1402 #endif
1403 }
1404
1405
1406 /* Draw the console */
1407 void con_draw(void)
1408 {
1409 #ifdef CONSOLE
1410         CON_DrawConsole(Console);
1411 #else
1412 #if 0
1413         char buffer[CON_LINE_LEN+1];
1414         int i,j;
1415         for (i = con_line, j=0; j < 20; i = (i+1) % CON_NUM_LINES, j++)
1416         {
1417                 memcpy(buffer, con_display[i], CON_LINE_LEN);
1418                 buffer[CON_LINE_LEN] = 0;
1419                 gr_string(1,j*10,buffer);
1420         }
1421 #endif
1422 #endif
1423 }
1424
1425 /* Show the console */
1426 void con_show(void)
1427 {
1428         Console_open = 1;
1429 #ifdef CONSOLE
1430         CON_Show(Console);
1431         CON_Topmost(Console);
1432 #endif
1433 }
1434
1435 void con_hide(void)
1436 {
1437         Console_open = 0;
1438 }
1439
1440 #ifdef CONSOLE
1441 void con_parse(ConsoleInformation *console, char *command)
1442 {
1443         cmd_parse(command);
1444 }
1445 #endif