]> icculus.org git repositories - divverent/darkplaces.git/blob - console.c
uncommented a lot of GL functions
[divverent/darkplaces.git] / console.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // console.c
21
22 #ifdef NeXT
23 #include <libc.h>
24 #endif
25 #ifndef _MSC_VER
26 #ifndef __BORLANDC__
27 #include <unistd.h>
28 #endif
29 #endif
30 #ifdef WIN32
31 #include <io.h>
32 #endif
33 #include <fcntl.h>
34 #include "quakedef.h"
35
36 int con_linewidth;
37
38 float con_cursorspeed = 4;
39
40 #define         CON_TEXTSIZE    131072
41
42 // total lines in console scrollback
43 int con_totallines;
44 // lines up from bottom to display
45 int con_backscroll;
46 // where next message will be printed
47 int con_current;
48 // offset in current line for next print
49 int con_x;
50 char *con_text = 0;
51
52 //seconds
53 cvar_t con_notifytime = {CVAR_SAVE, "con_notifytime","3"};
54 cvar_t con_notify = {CVAR_SAVE, "con_notify","4"};
55 cvar_t logfile = {0, "logfile","0"};
56
57 #define MAX_NOTIFYLINES 32
58 // cl.time time the line was generated for transparent notify lines
59 float con_times[MAX_NOTIFYLINES];
60
61 int con_vislines;
62
63 qboolean con_debuglog;
64
65 #define MAXCMDLINE      256
66 extern char key_lines[32][MAXCMDLINE];
67 extern int edit_line;
68 extern int key_linepos;
69 extern int key_insert;
70
71
72 qboolean con_initialized;
73
74 mempool_t *console_mempool;
75
76 extern void M_Menu_Main_f (void);
77
78 /*
79 ================
80 Con_ToggleConsole_f
81 ================
82 */
83 void Con_ToggleConsole_f (void)
84 {
85         // toggle the 'user wants console' bit
86         key_consoleactive ^= KEY_CONSOLEACTIVE_USER;
87         memset (con_times, 0, sizeof(con_times));
88 }
89
90 /*
91 ================
92 Con_Clear_f
93 ================
94 */
95 void Con_Clear_f (void)
96 {
97         if (con_text)
98                 memset (con_text, ' ', CON_TEXTSIZE);
99 }
100
101
102 /*
103 ================
104 Con_ClearNotify
105 ================
106 */
107 void Con_ClearNotify (void)
108 {
109         int i;
110
111         for (i=0 ; i<MAX_NOTIFYLINES ; i++)
112                 con_times[i] = 0;
113 }
114
115
116 /*
117 ================
118 Con_MessageMode_f
119 ================
120 */
121 void Con_MessageMode_f (void)
122 {
123         key_dest = key_message;
124         chat_team = false;
125 }
126
127
128 /*
129 ================
130 Con_MessageMode2_f
131 ================
132 */
133 void Con_MessageMode2_f (void)
134 {
135         key_dest = key_message;
136         chat_team = true;
137 }
138
139
140 /*
141 ================
142 Con_CheckResize
143
144 If the line width has changed, reformat the buffer.
145 ================
146 */
147 void Con_CheckResize (void)
148 {
149         int i, j, width, oldwidth, oldtotallines, numlines, numchars;
150         char tbuf[CON_TEXTSIZE];
151
152         width = (vid.conwidth >> 3);
153
154         if (width == con_linewidth)
155                 return;
156
157         if (width < 1)                  // video hasn't been initialized yet
158         {
159                 width = 80;
160                 con_linewidth = width;
161                 con_totallines = CON_TEXTSIZE / con_linewidth;
162                 memset (con_text, ' ', CON_TEXTSIZE);
163         }
164         else
165         {
166                 oldwidth = con_linewidth;
167                 con_linewidth = width;
168                 oldtotallines = con_totallines;
169                 con_totallines = CON_TEXTSIZE / con_linewidth;
170                 numlines = oldtotallines;
171
172                 if (con_totallines < numlines)
173                         numlines = con_totallines;
174
175                 numchars = oldwidth;
176
177                 if (con_linewidth < numchars)
178                         numchars = con_linewidth;
179
180                 memcpy (tbuf, con_text, CON_TEXTSIZE);
181                 memset (con_text, ' ', CON_TEXTSIZE);
182
183                 for (i=0 ; i<numlines ; i++)
184                 {
185                         for (j=0 ; j<numchars ; j++)
186                         {
187                                 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
188                                                 tbuf[((con_current - i + oldtotallines) %
189                                                           oldtotallines) * oldwidth + j];
190                         }
191                 }
192
193                 Con_ClearNotify ();
194         }
195
196         con_backscroll = 0;
197         con_current = con_totallines - 1;
198 }
199
200
201 void Con_InitLogging (void)
202 {
203 #define MAXGAMEDIRLEN 1000
204         char temp[MAXGAMEDIRLEN+1];
205         char *t2 = "/qconsole.log";
206
207         con_debuglog = COM_CheckParm("-condebug");
208         if (con_debuglog)
209         {
210                 if (strlen (fs_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
211                 {
212                         sprintf (temp, "%s%s", fs_gamedir, t2);
213                         unlink (temp);
214                 }
215                 logfile.integer = 1;
216         }
217 }
218
219 /*
220 ================
221 Con_Init
222 ================
223 */
224 void Con_Init (void)
225 {
226         Cvar_RegisterVariable(&logfile);
227
228         console_mempool = Mem_AllocPool("console");
229         con_text = Mem_Alloc(console_mempool, CON_TEXTSIZE);
230         memset (con_text, ' ', CON_TEXTSIZE);
231         con_linewidth = -1;
232         Con_CheckResize ();
233
234         Con_Print("Console initialized.\n");
235
236 //
237 // register our commands
238 //
239         Cvar_RegisterVariable (&con_notifytime);
240         Cvar_RegisterVariable (&con_notify);
241
242         Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
243         Cmd_AddCommand ("messagemode", Con_MessageMode_f);
244         Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
245         Cmd_AddCommand ("clear", Con_Clear_f);
246         con_initialized = true;
247 }
248
249
250 /*
251 ===============
252 Con_Linefeed
253 ===============
254 */
255 void Con_Linefeed (void)
256 {
257         con_x = 0;
258         con_current++;
259         memset (&con_text[(con_current%con_totallines)*con_linewidth], ' ', con_linewidth);
260 }
261
262 /*
263 ================
264 Con_PrintToHistory
265
266 Handles cursor positioning, line wrapping, etc
267 All console printing must go through this in order to be displayed
268 If no console is visible, the notify window will pop up.
269 ================
270 */
271 void Con_PrintToHistory(const char *txt)
272 {
273         int y, c, l, mask;
274         static int cr;
275
276         con_backscroll = 0;
277
278         if (txt[0] == 1)
279         {
280                 mask = 128;             // go to colored text
281                 S_LocalSound ("misc/talk.wav");
282         // play talk wav
283                 txt++;
284         }
285         else if (txt[0] == 2)
286         {
287                 mask = 128;             // go to colored text
288                 txt++;
289         }
290         else
291                 mask = 0;
292
293
294         while ( (c = *txt) )
295         {
296         // count word length
297                 for (l=0 ; l< con_linewidth ; l++)
298                         if ( txt[l] <= ' ')
299                                 break;
300
301         // word wrap
302                 if (l != con_linewidth && (con_x + l > con_linewidth) )
303                         con_x = 0;
304
305                 txt++;
306
307                 if (cr)
308                 {
309                         con_current--;
310                         cr = false;
311                 }
312
313
314                 if (!con_x)
315                 {
316                         Con_Linefeed ();
317                 // mark time for transparent overlay
318                         if (con_current >= 0)
319                         {
320                                 if (con_notify.integer < 0)
321                                         Cvar_SetValueQuick(&con_notify, 0);
322                                 if (con_notify.integer > MAX_NOTIFYLINES)
323                                         Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
324                                 if (con_notify.integer > 0)
325                                         con_times[con_current % con_notify.integer] = cl.time;
326                         }
327                 }
328
329                 switch (c)
330                 {
331                 case '\n':
332                         con_x = 0;
333                         break;
334
335                 case '\r':
336                         con_x = 0;
337                         cr = 1;
338                         break;
339
340                 default:        // display character and advance
341                         y = con_current % con_totallines;
342                         con_text[y*con_linewidth+con_x] = c | mask;
343                         con_x++;
344                         if (con_x >= con_linewidth)
345                                 con_x = 0;
346                         break;
347                 }
348
349         }
350 }
351
352 // LordHavoc: increased from 4096 to 16384
353 #define MAXPRINTMSG     16384
354
355 /*
356 ================
357 Con_LogPrint
358 ================
359 */
360 void Con_LogPrint(const char *logfilename, const char *msg)
361 {
362         qfile_t *file;
363         file = FS_Open(logfilename, "at", true);
364         if (file)
365         {
366                 FS_Print(file, msg);
367                 FS_Close(file);
368         }
369 }
370
371 /*
372 ================
373 Con_LogPrintf
374 ================
375 */
376 void Con_LogPrintf(const char *logfilename, const char *fmt, ...)
377 {
378         va_list argptr;
379         char msg[MAXPRINTMSG];
380
381         va_start(argptr,fmt);
382         vsprintf(msg,fmt,argptr);
383         va_end(argptr);
384
385         Con_LogPrint(logfilename, msg);
386 }
387
388 /*
389 ================
390 Con_Print
391
392 Prints to all appropriate console targets
393 ================
394 */
395 void Con_Print(const char *msg)
396 {
397         // also echo to debugging console
398         Sys_Print(msg);
399
400         // log all messages to file
401         if (con_debuglog)
402                 Con_LogPrint("qconsole.log", msg);
403
404         if (!con_initialized)
405                 return;
406
407         if (cls.state == ca_dedicated)
408                 return;         // no graphics mode
409
410         // write it to the scrollable buffer
411         Con_PrintToHistory(msg);
412 }
413
414 /*
415 ================
416 Con_Printf
417
418 Prints to all appropriate console targets
419 ================
420 */
421 void Con_Printf(const char *fmt, ...)
422 {
423         va_list argptr;
424         char msg[MAXPRINTMSG];
425
426         va_start(argptr,fmt);
427         vsprintf(msg,fmt,argptr);
428         va_end(argptr);
429
430         Con_Print(msg);
431 }
432
433 /*
434 ================
435 Con_DPrint
436
437 A Con_Print that only shows up if the "developer" cvar is set
438 ================
439 */
440 void Con_DPrint(const char *msg)
441 {
442         if (!developer.integer)
443                 return;                 // don't confuse non-developers with techie stuff...
444         Con_Print(msg);
445 }
446
447 /*
448 ================
449 Con_DPrintf
450
451 A Con_Printf that only shows up if the "developer" cvar is set
452 ================
453 */
454 void Con_DPrintf(const char *fmt, ...)
455 {
456         va_list argptr;
457         char msg[MAXPRINTMSG];
458
459         if (!developer.integer)
460                 return;                 // don't confuse non-developers with techie stuff...
461
462         va_start(argptr,fmt);
463         vsprintf(msg,fmt,argptr);
464         va_end(argptr);
465
466         Con_Print(msg);
467 }
468
469
470 /*
471 ================
472 Con_SafePrint
473
474 Okay to call even when the screen can't be updated
475 ==================
476 */
477 void Con_SafePrint(const char *msg)
478 {
479         Con_Print(msg);
480 }
481
482 /*
483 ==================
484 Con_SafePrintf
485
486 Okay to call even when the screen can't be updated
487 ==================
488 */
489 void Con_SafePrintf(const char *fmt, ...)
490 {
491         va_list argptr;
492         char msg[MAXPRINTMSG];
493
494         va_start(argptr,fmt);
495         vsprintf(msg,fmt,argptr);
496         va_end(argptr);
497
498         Con_Print(msg);
499 }
500
501
502 /*
503 ==============================================================================
504
505 DRAWING
506
507 ==============================================================================
508 */
509
510
511 /*
512 ================
513 Con_DrawInput
514
515 The input line scrolls horizontally if typing goes beyond the right edge
516
517 Modified by EvilTypeGuy eviltypeguy@qeradiant.com
518 ================
519 */
520 void Con_DrawInput (void)
521 {
522         char editlinecopy[257], *text;
523
524         if (!key_consoleactive)
525                 return;         // don't draw anything
526
527         text = strcpy(editlinecopy, key_lines[edit_line]);
528
529         // Advanced Console Editing by Radix radix@planetquake.com
530         // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
531         // use strlen of edit_line instead of key_linepos to allow editing
532         // of early characters w/o erasing
533
534         // add the cursor frame
535         if ((int)(realtime*con_cursorspeed) & 1)                // cursor is visible
536                 text[key_linepos] = 11 + 130 * key_insert;      // either solid or triangle facing right
537
538         text[key_linepos + 1] = 0;
539
540         // prestep if horizontally scrolling
541         if (key_linepos >= con_linewidth)
542                 text += 1 + key_linepos - con_linewidth;
543
544         // draw it
545         DrawQ_String(0, con_vislines - 16, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
546
547         // remove cursor
548         key_lines[edit_line][key_linepos] = 0;
549 }
550
551
552 /*
553 ================
554 Con_DrawNotify
555
556 Draws the last few lines of output transparently over the game top
557 ================
558 */
559 void Con_DrawNotify (void)
560 {
561         int             x, v;
562         char    *text;
563         int             i;
564         float   time;
565         extern char chat_buffer[];
566         char    temptext[256];
567
568         if (con_notify.integer < 0)
569                 Cvar_SetValueQuick(&con_notify, 0);
570         if (con_notify.integer > MAX_NOTIFYLINES)
571                 Cvar_SetValueQuick(&con_notify, MAX_NOTIFYLINES);
572         v = 0;
573         for (i= con_current-con_notify.integer+1 ; i<=con_current ; i++)
574         {
575                 if (i < 0)
576                         continue;
577                 time = con_times[i % con_notify.integer];
578                 if (time == 0)
579                         continue;
580                 time = cl.time - time;
581                 if (time > con_notifytime.value)
582                         continue;
583                 text = con_text + (i % con_totallines)*con_linewidth;
584
585                 clearnotify = 0;
586
587                 DrawQ_String(0, v, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
588
589                 v += 8;
590         }
591
592
593         if (key_dest == key_message)
594         {
595                 clearnotify = 0;
596
597                 x = 0;
598
599                 // LordHavoc: speedup, and other improvements
600                 if (chat_team)
601                         sprintf(temptext, "say_team:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
602                 else
603                         sprintf(temptext, "say:%s%c", chat_buffer, (int) 10+((int)(realtime*con_cursorspeed)&1));
604                 while (strlen(temptext) >= (size_t) con_linewidth)
605                 {
606                         DrawQ_String (0, v, temptext, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
607                         strcpy(temptext, &temptext[con_linewidth]);
608                         v += 8;
609                 }
610                 if (strlen(temptext) > 0)
611                 {
612                         DrawQ_String (0, v, temptext, 0, 8, 8, 1, 1, 1, 1, 0);
613                         v += 8;
614                 }
615         }
616 }
617
618 /*
619 ================
620 Con_DrawConsole
621
622 Draws the console with the solid background
623 The typing input line at the bottom should only be drawn if typing is allowed
624 ================
625 */
626 extern char engineversion[40];
627 void Con_DrawConsole (int lines)
628 {
629         int i, y, rows, j;
630         char *text;
631
632         if (lines <= 0)
633                 return;
634
635 // draw the background
636         if (scr_conbrightness.value >= 0.01f)
637                 DrawQ_Pic(0, lines - vid.conheight, "gfx/conback", vid.conwidth, vid.conheight, scr_conbrightness.value, scr_conbrightness.value, scr_conbrightness.value, scr_conalpha.value, 0);
638         else
639                 DrawQ_Fill(0, lines - vid.conheight, vid.conwidth, vid.conheight, 0, 0, 0, scr_conalpha.value, 0);
640         DrawQ_String(vid.conwidth - strlen(engineversion) * 8 - 8, lines - 8, engineversion, 0, 8, 8, 1, 0, 0, 1, 0);
641
642 // draw the text
643         con_vislines = lines;
644
645         rows = (lines-16)>>3;           // rows of text to draw
646         y = lines - 16 - (rows<<3);     // may start slightly negative
647
648         for (i = con_current - rows + 1;i <= con_current;i++, y += 8)
649         {
650                 j = max(i - con_backscroll, 0);
651                 text = con_text + (j % con_totallines)*con_linewidth;
652
653                 DrawQ_String(0, y, text, con_linewidth, 8, 8, 1, 1, 1, 1, 0);
654         }
655
656 // draw the input prompt, user text, and cursor if desired
657         Con_DrawInput ();
658 }
659
660 /*
661         Con_DisplayList
662
663         New function for tab-completion system
664         Added by EvilTypeGuy
665         MEGA Thanks to Taniwha
666
667 */
668 void Con_DisplayList(const char **list)
669 {
670         int i = 0, pos = 0, len = 0, maxlen = 0, width = (con_linewidth - 4);
671         const char **walk = list;
672
673         while (*walk) {
674                 len = strlen(*walk);
675                 if (len > maxlen)
676                         maxlen = len;
677                 walk++;
678         }
679         maxlen += 1;
680
681         while (*list) {
682                 len = strlen(*list);
683                 if (pos + maxlen >= width) {
684                         Con_Print("\n");
685                         pos = 0;
686                 }
687
688                 Con_Print(*list);
689                 for (i = 0; i < (maxlen - len); i++)
690                         Con_Print(" ");
691
692                 pos += maxlen;
693                 list++;
694         }
695
696         if (pos)
697                 Con_Print("\n\n");
698 }
699
700 /*
701         Con_CompleteCommandLine
702
703         New function for tab-completion system
704         Added by EvilTypeGuy
705         Thanks to Fett erich@heintz.com
706         Thanks to taniwha
707
708 */
709 void Con_CompleteCommandLine (void)
710 {
711         const char *cmd = "", *s;
712         const char **list[3] = {0, 0, 0};
713         int c, v, a, i, cmd_len;
714
715         s = key_lines[edit_line] + 1;
716         // Count number of possible matches
717         c = Cmd_CompleteCountPossible(s);
718         v = Cvar_CompleteCountPossible(s);
719         a = Cmd_CompleteAliasCountPossible(s);
720
721         if (!(c + v + a))       // No possible matches
722                 return;
723
724         if (c + v + a == 1) {
725                 if (c)
726                         list[0] = Cmd_CompleteBuildList(s);
727                 else if (v)
728                         list[0] = Cvar_CompleteBuildList(s);
729                 else
730                         list[0] = Cmd_CompleteAliasBuildList(s);
731                 cmd = *list[0];
732                 cmd_len = strlen (cmd);
733         } else {
734                 if (c)
735                         cmd = *(list[0] = Cmd_CompleteBuildList(s));
736                 if (v)
737                         cmd = *(list[1] = Cvar_CompleteBuildList(s));
738                 if (a)
739                         cmd = *(list[2] = Cmd_CompleteAliasBuildList(s));
740
741                 cmd_len = strlen (s);
742                 do {
743                         for (i = 0; i < 3; i++) {
744                                 char ch = cmd[cmd_len];
745                                 const char **l = list[i];
746                                 if (l) {
747                                         while (*l && (*l)[cmd_len] == ch)
748                                                 l++;
749                                         if (*l)
750                                                 break;
751                                 }
752                         }
753                         if (i == 3)
754                                 cmd_len++;
755                 } while (i == 3);
756                 // 'quakebar'
757                 Con_Print("\n\35");
758                 for (i = 0; i < con_linewidth - 4; i++)
759                         Con_Print("\36");
760                 Con_Print("\37\n");
761
762                 // Print Possible Commands
763                 if (c) {
764                         Con_Printf("%i possible command%s\n", c, (c > 1) ? "s: " : ":");
765                         Con_DisplayList(list[0]);
766                 }
767
768                 if (v) {
769                         Con_Printf("%i possible variable%s\n", v, (v > 1) ? "s: " : ":");
770                         Con_DisplayList(list[1]);
771                 }
772
773                 if (a) {
774                         Con_Printf("%i possible aliases%s\n", a, (a > 1) ? "s: " : ":");
775                         Con_DisplayList(list[2]);
776                 }
777         }
778
779         if (cmd) {
780                 strncpy(key_lines[edit_line] + 1, cmd, cmd_len);
781                 key_linepos = cmd_len + 1;
782                 if (c + v + a == 1) {
783                         key_lines[edit_line][key_linepos] = ' ';
784                         key_linepos++;
785                 }
786                 key_lines[edit_line][key_linepos] = 0;
787         }
788         for (i = 0; i < 3; i++)
789                 if (list[i])
790                         Mem_Free((void *)list[i]);
791 }
792