git-svn-id: http://bladebattles.com/kurok/SVN@11 20cd92bb-ff49-0410-b73e-96a06e42c3b9
[kurok.git] / screen.c
blob8251e0eaf00b8f2fe15f15f17fd9dda314197c15
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // screen.c -- master for refresh, status bar, console, chat, notify, etc
22 #include "quakedef.h"
23 #include "r_local.h"
25 // only the refresh window will be updated unless these variables are flagged
26 int scr_copytop;
27 int scr_copyeverything;
29 float scr_con_current;
30 float scr_conlines; // lines of console to display
32 float oldscreensize, oldfov;
33 cvar_t scr_viewsize = {"viewsize","100", true};
34 cvar_t scr_fov = {"fov","90"}; // 10 - 170
35 cvar_t scr_conspeed = {"scr_conspeed","300"};
36 cvar_t scr_centertime = {"scr_centertime","2"};
37 cvar_t scr_showram = {"showram","1"};
38 cvar_t scr_showturtle = {"showturtle","0"};
39 cvar_t scr_showpause = {"showpause","1"};
40 cvar_t scr_printspeed = {"scr_printspeed","8"};
42 qboolean scr_initialized; // ready to draw
44 qpic_t *scr_ram;
45 qpic_t *scr_net;
46 qpic_t *scr_turtle;
48 int scr_fullupdate;
50 int clearconsole;
51 int clearnotify;
53 viddef_t vid; // global video state
55 vrect_t *pconupdate;
56 vrect_t scr_vrect;
58 qboolean scr_disabled_for_loading;
59 qboolean scr_drawloading;
60 float scr_disabled_time;
61 qboolean scr_skipupdate;
63 qboolean block_drawing;
65 void SCR_ScreenShot_f (void);
68 ===============================================================================
70 CENTER PRINTING
72 ===============================================================================
75 char scr_centerstring[1024];
76 float scr_centertime_start; // for slow victory printing
77 float scr_centertime_off;
78 int scr_center_lines;
79 int scr_erase_lines;
80 int scr_erase_center;
83 ==============
84 SCR_CenterPrint
86 Called for important messages that should stay in the center of the screen
87 for a few moments
88 ==============
90 void SCR_CenterPrint (char *str)
92 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
93 scr_centertime_off = scr_centertime.value;
94 scr_centertime_start = cl.time;
96 // count the number of lines for centering
97 scr_center_lines = 1;
98 while (*str)
100 if (*str == '\n')
101 scr_center_lines++;
102 str++;
106 void SCR_EraseCenterString (void)
108 int y;
110 if (scr_erase_center++ > vid.numpages)
112 scr_erase_lines = 0;
113 return;
116 if (scr_center_lines <= 4)
117 y = vid.height*0.35;
118 else
119 y = 48;
121 scr_copytop = 1;
122 Draw_TileClear (0, y,vid.width, 8*scr_erase_lines);
125 void SCR_DrawCenterString (void)
127 char *start;
128 int l;
129 int j;
130 int x, y;
131 int remaining;
133 // the finale prints the characters one at a time
134 if (cl.intermission)
135 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
136 else
137 remaining = 9999;
139 scr_erase_center = 0;
140 start = scr_centerstring;
142 if (scr_center_lines <= 4)
143 y = vid.height*0.35;
144 else
145 y = 48;
149 // scan the width of the line
150 for (l=0 ; l<40 ; l++)
151 if (start[l] == '\n' || !start[l])
152 break;
153 x = (vid.width - l*8)/2;
154 for (j=0 ; j<l ; j++, x+=8)
156 Draw_Character (x, y, start[j]);
157 if (!remaining--)
158 return;
161 y += 8;
163 while (*start && *start != '\n')
164 start++;
166 if (!*start)
167 break;
168 start++; // skip the \n
169 } while (1);
172 void SCR_CheckDrawCenterString (void)
174 scr_copytop = 1;
175 if (scr_center_lines > scr_erase_lines)
176 scr_erase_lines = scr_center_lines;
178 scr_centertime_off -= host_frametime;
180 if (scr_centertime_off <= 0 && !cl.intermission)
181 return;
182 if (key_dest != key_game)
183 return;
185 SCR_DrawCenterString ();
188 //=============================================================================
191 ====================
192 CalcFov
193 ====================
195 float CalcFov (float fov_x, float width, float height)
197 float a;
198 float x;
200 if (fov_x < 1 || fov_x > 179)
201 Sys_Error ("Bad fov: %f", fov_x);
203 x = width/tanf(fov_x/360*M_PI);
205 a = atanf(height/x);
207 a = a*360/M_PI;
209 return a;
213 =================
214 SCR_CalcRefdef
216 Must be called whenever vid changes
217 Internal use only
218 =================
220 static void SCR_CalcRefdef (void)
222 vrect_t vrect;
223 float size;
225 scr_fullupdate = 0; // force a background redraw
226 vid.recalc_refdef = 0;
228 // force the status bar to redraw
229 Sbar_Changed ();
231 //========================================
233 // bound viewsize
234 if (scr_viewsize.value < 30)
235 Cvar_Set ("viewsize","30");
236 if (scr_viewsize.value > 130)
237 Cvar_Set ("viewsize","130");
239 // bound field of view
240 if (scr_fov.value < 10)
241 Cvar_Set ("fov","10");
242 if (scr_fov.value > 170)
243 Cvar_Set ("fov","170");
245 r_refdef.fov_x = scr_fov.value;
246 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
248 // intermission is always full screen
249 if (cl.intermission)
250 size = 130;
251 else
252 size = scr_viewsize.value;
254 if (size >= 130)
255 sb_lines = 0; // no status bar at all
256 else if (size >= 120)
257 sb_lines = 24; // no inventory
258 else
259 sb_lines = 24+16+8;
261 // these calculations mirror those in R_Init() for r_refdef, but take no
262 // account of water warping
263 vrect.x = 0;
264 vrect.y = 0;
265 vrect.width = vid.width;
266 vrect.height = vid.height;
268 R_SetVrect (&vrect, &scr_vrect, sb_lines);
270 // guard against going from one mode to another that's less than half the
271 // vertical resolution
272 if (scr_con_current > vid.height)
273 scr_con_current = vid.height;
275 // notify the refresh of the change
276 R_ViewChanged (&vrect, sb_lines, vid.aspect);
281 =================
282 SCR_SizeUp_f
284 Keybinding command
285 =================
287 void SCR_SizeUp_f (void)
289 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
290 vid.recalc_refdef = 1;
295 =================
296 SCR_SizeDown_f
298 Keybinding command
299 =================
301 void SCR_SizeDown_f (void)
303 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
304 vid.recalc_refdef = 1;
307 //============================================================================
310 ==================
311 SCR_Init
312 ==================
314 void SCR_Init (void)
316 Cvar_RegisterVariable (&scr_fov);
317 Cvar_RegisterVariable (&scr_viewsize);
318 Cvar_RegisterVariable (&scr_conspeed);
319 Cvar_RegisterVariable (&scr_showram);
320 Cvar_RegisterVariable (&scr_showturtle);
321 Cvar_RegisterVariable (&scr_showpause);
322 Cvar_RegisterVariable (&scr_centertime);
323 Cvar_RegisterVariable (&scr_printspeed);
326 // register our commands
328 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
329 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
330 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
332 scr_ram = Draw_PicFromWad ("ram");
333 scr_net = Draw_PicFromWad ("net");
334 scr_turtle = Draw_PicFromWad ("turtle");
336 scr_initialized = true;
342 ==============
343 SCR_DrawRam
344 ==============
346 void SCR_DrawRam (void)
348 if (!scr_showram.value)
349 return;
351 if (!r_cache_thrash)
352 return;
354 Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
358 ==============
359 SCR_DrawTurtle
360 ==============
362 void SCR_DrawTurtle (void)
364 static int count;
366 if (!scr_showturtle.value)
367 return;
369 if (host_frametime < 0.1)
371 count = 0;
372 return;
375 count++;
376 if (count < 3)
377 return;
379 Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
383 ==============
384 SCR_DrawNet
385 ==============
387 void SCR_DrawNet (void)
389 if (realtime - cl.last_received_message < 0.3)
390 return;
391 if (cls.demoplayback)
392 return;
394 Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
398 ==============
399 DrawPause
400 ==============
402 void SCR_DrawPause (void)
404 qpic_t *pic;
406 if (!scr_showpause.value) // turn off for screenshots
407 return;
409 if (!cl.paused)
410 return;
412 pic = Draw_CachePic ("gfx/pause.lmp");
413 Draw_Pic ( (vid.width - pic->width)/2,
414 (vid.height - 48 - pic->height)/2, pic);
420 ==============
421 SCR_DrawLoading
422 ==============
424 void SCR_DrawLoading (void)
426 qpic_t *pic;
428 if (!scr_drawloading)
429 return;
431 pic = Draw_CachePic ("gfx/loading.lmp");
432 Draw_Pic ( (vid.width - pic->width)/2,
433 (vid.height - 48 - pic->height)/2, pic);
438 //=============================================================================
442 ==================
443 SCR_SetUpToDrawConsole
444 ==================
446 void SCR_SetUpToDrawConsole (void)
448 Con_CheckResize ();
450 if (scr_drawloading)
451 return; // never a console with loading plaque
453 // decide on the height of the console
454 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
456 if (con_forcedup)
458 scr_conlines = vid.height; // full screen
459 scr_con_current = scr_conlines;
461 else if (key_dest == key_console)
462 scr_conlines = vid.height/2; // half screen
463 else
464 scr_conlines = 0; // none visible
466 if (scr_conlines < scr_con_current)
468 scr_con_current -= scr_conspeed.value*host_frametime;
469 if (scr_conlines > scr_con_current)
470 scr_con_current = scr_conlines;
473 else if (scr_conlines > scr_con_current)
475 scr_con_current += scr_conspeed.value*host_frametime;
476 if (scr_conlines < scr_con_current)
477 scr_con_current = scr_conlines;
480 if (clearconsole++ < vid.numpages)
482 scr_copytop = 1;
483 Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current);
484 Sbar_Changed ();
486 else if (clearnotify++ < vid.numpages)
488 scr_copytop = 1;
489 Draw_TileClear (0,0,vid.width, con_notifylines);
491 else
492 con_notifylines = 0;
496 ==================
497 SCR_DrawConsole
498 ==================
500 void SCR_DrawConsole (void)
502 if (scr_con_current)
504 scr_copyeverything = 1;
505 Con_DrawConsole (scr_con_current, true);
506 clearconsole = 0;
508 else
510 if (key_dest == key_game || key_dest == key_message)
511 Con_DrawNotify (); // only draw notify in game
517 ==============================================================================
519 SCREEN SHOTS
521 ==============================================================================
525 typedef struct
527 char manufacturer;
528 char version;
529 char encoding;
530 char bits_per_pixel;
531 unsigned short xmin,ymin,xmax,ymax;
532 unsigned short hres,vres;
533 unsigned char palette[48];
534 char reserved;
535 char color_planes;
536 unsigned short bytes_per_line;
537 unsigned short palette_type;
538 char filler[58];
539 unsigned char data; // unbounded
540 } pcx_t;
543 ==============
544 WritePCXfile
545 ==============
547 void WritePCXfile (char *filename, byte *data, int width, int height,
548 int rowbytes, byte *palette)
550 int i, j, length;
551 pcx_t *pcx;
552 byte *pack;
554 pcx = Hunk_TempAlloc (width*height*2+1000);
555 if (pcx == NULL)
557 Con_Printf("SCR_ScreenShot_f: not enough memory\n");
558 return;
561 pcx->manufacturer = 0x0a; // PCX id
562 pcx->version = 5; // 256 color
563 pcx->encoding = 1; // uncompressed
564 pcx->bits_per_pixel = 8; // 256 color
565 pcx->xmin = 0;
566 pcx->ymin = 0;
567 pcx->xmax = LittleShort((short)(width-1));
568 pcx->ymax = LittleShort((short)(height-1));
569 pcx->hres = LittleShort((short)width);
570 pcx->vres = LittleShort((short)height);
571 Q_memset (pcx->palette,0,sizeof(pcx->palette));
572 pcx->color_planes = 1; // chunky image
573 pcx->bytes_per_line = LittleShort((short)width);
574 pcx->palette_type = LittleShort(2); // not a grey scale
575 Q_memset (pcx->filler,0,sizeof(pcx->filler));
577 // pack the image
578 pack = &pcx->data;
580 for (i=0 ; i<height ; i++)
582 for (j=0 ; j<width ; j++)
584 if ( (*data & 0xc0) != 0xc0)
585 *pack++ = *data++;
586 else
588 *pack++ = 0xc1;
589 *pack++ = *data++;
593 data += rowbytes - width;
596 // write the palette
597 *pack++ = 0x0c; // palette ID byte
598 for (i=0 ; i<768 ; i++)
599 *pack++ = *palette++;
601 // write output file
602 length = pack - (byte *)pcx;
603 COM_WriteFile (filename, pcx, length);
609 ==================
610 SCR_ScreenShot_f
611 ==================
613 void SCR_ScreenShot_f (void)
615 int i;
616 char pcxname[80];
617 char checkname[MAX_OSPATH];
620 // find a file name to save it to
622 strcpy(pcxname,"quake00.pcx");
624 for (i=0 ; i<=99 ; i++)
626 pcxname[5] = i/10 + '0';
627 pcxname[6] = i%10 + '0';
628 sprintf (checkname, "%s/%s", com_gamedir, pcxname);
629 if (Sys_FileTime(checkname) == -1)
630 break; // file doesn't exist
632 if (i==100)
634 Con_Printf ("SCR_ScreenShot_f: Couldn't create a PCX file\n");
635 return;
639 // save the pcx file
641 D_EnableBackBufferAccess (); // enable direct drawing of console to back
642 // buffer
644 WritePCXfile (pcxname, vid.buffer, vid.width, vid.height, vid.rowbytes,
645 host_basepal);
647 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
648 // for linear writes all the time
650 Con_Printf ("Wrote %s\n", pcxname);
654 //=============================================================================
658 ===============
659 SCR_BeginLoadingPlaque
661 ================
663 void SCR_BeginLoadingPlaque (void)
665 S_StopAllSounds (true);
667 if (cls.state != ca_connected)
668 return;
669 if (cls.signon != SIGNONS)
670 return;
672 // redraw with no console and the loading plaque
673 Con_ClearNotify ();
674 scr_centertime_off = 0;
675 scr_con_current = 0;
677 scr_drawloading = true;
678 scr_fullupdate = 0;
679 Sbar_Changed ();
680 SCR_UpdateScreen ();
681 scr_drawloading = false;
683 scr_disabled_for_loading = true;
684 scr_disabled_time = realtime;
685 scr_fullupdate = 0;
689 ===============
690 SCR_EndLoadingPlaque
692 ================
694 void SCR_EndLoadingPlaque (void)
696 scr_disabled_for_loading = false;
697 scr_fullupdate = 0;
698 Con_ClearNotify ();
701 //=============================================================================
703 char *scr_notifystring;
704 qboolean scr_drawdialog;
706 void SCR_DrawNotifyString (void)
708 char *start;
709 int l;
710 int j;
711 int x, y;
713 start = scr_notifystring;
715 y = vid.height*0.35;
719 // scan the width of the line
720 for (l=0 ; l<40 ; l++)
721 if (start[l] == '\n' || !start[l])
722 break;
723 x = (vid.width - l*8)/2;
724 for (j=0 ; j<l ; j++, x+=8)
725 Draw_Character (x, y, start[j]);
727 y += 8;
729 while (*start && *start != '\n')
730 start++;
732 if (!*start)
733 break;
734 start++; // skip the \n
735 } while (1);
739 ==================
740 SCR_ModalMessage
742 Displays a text string in the center of the screen and waits for a Y or N
743 keypress.
744 ==================
746 int SCR_ModalMessage (char *text)
748 if (cls.state == ca_dedicated)
749 return true;
751 scr_notifystring = text;
753 // draw a fresh screen
754 scr_fullupdate = 0;
755 scr_drawdialog = true;
756 SCR_UpdateScreen ();
757 scr_drawdialog = false;
759 S_ClearBuffer (); // so dma doesn't loop current sound
763 key_count = -1; // wait for a key down and up
764 Sys_SendKeyEvents ();
765 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
767 scr_fullupdate = 0;
768 SCR_UpdateScreen ();
770 return key_lastpress == 'y';
774 //=============================================================================
777 ===============
778 SCR_BringDownConsole
780 Brings the console down and fades the palettes back to normal
781 ================
783 void SCR_BringDownConsole (void)
785 int i;
787 scr_centertime_off = 0;
789 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
790 SCR_UpdateScreen ();
792 cl.cshifts[0].percent = 0; // no area contents palette on next frame
793 VID_SetPalette (host_basepal);
798 ==================
799 SCR_UpdateScreen
801 This is called every frame, and can also be called explicitly to flush
802 text to the screen.
804 WARNING: be very careful calling this from elsewhere, because the refresh
805 needs almost the entire 256k of stack space!
806 ==================
808 void SCR_UpdateScreen (void)
810 static float oldscr_viewsize;
811 static float oldlcd_x;
812 vrect_t vrect;
814 if (scr_skipupdate || block_drawing)
815 return;
817 scr_copytop = 0;
818 scr_copyeverything = 0;
820 if (scr_disabled_for_loading)
822 if (realtime - scr_disabled_time > 60)
824 scr_disabled_for_loading = false;
825 Con_Printf ("load failed.\n");
827 else
828 return;
831 if (cls.state == ca_dedicated)
832 return; // stdout only
834 if (!scr_initialized || !con_initialized)
835 return; // not initialized yet
837 if (scr_viewsize.value != oldscr_viewsize)
839 oldscr_viewsize = scr_viewsize.value;
840 vid.recalc_refdef = 1;
844 // check for vid changes
846 if (oldfov != scr_fov.value)
848 oldfov = scr_fov.value;
849 vid.recalc_refdef = true;
852 if (oldlcd_x != lcd_x.value)
854 oldlcd_x = lcd_x.value;
855 vid.recalc_refdef = true;
858 if (oldscreensize != scr_viewsize.value)
860 oldscreensize = scr_viewsize.value;
861 vid.recalc_refdef = true;
864 if (vid.recalc_refdef)
866 // something changed, so reorder the screen
867 SCR_CalcRefdef ();
871 // do 3D refresh drawing, and then update the screen
873 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
875 if (scr_fullupdate++ < vid.numpages)
876 { // clear the entire screen
877 scr_copyeverything = 1;
878 Draw_TileClear (0,0,vid.width,vid.height);
879 Sbar_Changed ();
882 pconupdate = NULL;
885 SCR_SetUpToDrawConsole ();
886 SCR_EraseCenterString ();
888 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
889 // for linear writes all the time
891 VID_LockBuffer ();
893 V_RenderView ();
895 VID_UnlockBuffer ();
897 D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly
899 if (scr_drawdialog)
901 Sbar_Draw ();
902 Draw_FadeScreen ();
903 SCR_DrawNotifyString ();
904 scr_copyeverything = true;
906 else if (scr_drawloading)
908 SCR_DrawLoading ();
909 Sbar_Draw ();
911 else if (cl.intermission == 1 && key_dest == key_game)
913 Sbar_IntermissionOverlay ();
915 else if (cl.intermission == 2 && key_dest == key_game)
917 Sbar_FinaleOverlay ();
918 SCR_CheckDrawCenterString ();
920 else if (cl.intermission == 3 && key_dest == key_game)
922 SCR_CheckDrawCenterString ();
924 else
926 SCR_DrawRam ();
927 SCR_DrawNet ();
928 SCR_DrawTurtle ();
929 SCR_DrawPause ();
930 SCR_CheckDrawCenterString ();
931 Sbar_Draw ();
932 SCR_DrawConsole ();
933 M_Draw ();
936 D_DisableBackBufferAccess (); // for adapters that can't stay mapped in
937 // for linear writes all the time
938 if (pconupdate)
940 D_UpdateRects (pconupdate);
943 V_UpdatePalette ();
946 // update one of three areas
949 if (scr_copyeverything)
951 vrect.x = 0;
952 vrect.y = 0;
953 vrect.width = vid.width;
954 vrect.height = vid.height;
955 vrect.pnext = 0;
957 VID_Update (&vrect);
959 else if (scr_copytop)
961 vrect.x = 0;
962 vrect.y = 0;
963 vrect.width = vid.width;
964 vrect.height = vid.height - sb_lines;
965 vrect.pnext = 0;
967 VID_Update (&vrect);
969 else
971 vrect.x = scr_vrect.x;
972 vrect.y = scr_vrect.y;
973 vrect.width = scr_vrect.width;
974 vrect.height = scr_vrect.height;
975 vrect.pnext = 0;
977 VID_Update (&vrect);
983 ==================
984 SCR_UpdateWholeScreen
985 ==================
987 void SCR_UpdateWholeScreen (void)
989 scr_fullupdate = 0;
990 SCR_UpdateScreen ();