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.
21 // screen.c -- master for refresh, status bar, console, chat, notify, etc
31 centerprint / slow centerprint
33 intermission / finale overlay
38 required background clears
39 required update regions
42 syncronous draw mode or async
43 One off screen buffer, with updates either copied or xblited
44 Need to double buffer?
47 async draw will require the refresh area to be cleared, because it will be
48 xblited, but sync draw can just ignore it.
59 turn off messages option
61 the refresh is allways rendered, unless the console is full screen
73 int glx, gly, glwidth, glheight;
75 // only the refresh window will be updated unless these variables are flagged
77 int scr_copyeverything;
79 float scr_con_current;
80 float scr_conlines; // lines of console to display
82 float oldscreensize, oldfov;
83 cvar_t scr_viewsize = {"viewsize","100", true};
84 cvar_t scr_fov = {"fov","90"}; // 10 - 170
85 cvar_t scr_conspeed = {"scr_conspeed","300"};
86 cvar_t scr_centertime = {"scr_centertime","2"};
87 cvar_t scr_showram = {"showram","1"};
88 cvar_t scr_showturtle = {"showturtle","0"};
89 cvar_t scr_showpause = {"showpause","1"};
90 cvar_t scr_printspeed = {"scr_printspeed","8"};
91 cvar_t gl_triplebuffer = {"gl_triplebuffer", "1", true };
93 extern cvar_t crosshair;
95 qboolean scr_initialized; // ready to draw
108 viddef_t vid; // global video state
112 qboolean scr_disabled_for_loading;
113 qboolean scr_drawloading;
114 float scr_disabled_time;
116 void SCR_ScreenShot_f (void);
119 ===============================================================================
123 ===============================================================================
126 char scr_centerstring[1024];
127 float scr_centertime_start; // for slow victory printing
128 float scr_centertime_off;
129 int scr_center_lines;
131 int scr_erase_center;
137 Called for important messages that should stay in the center of the screen
141 void SCR_CenterPrint (char *str)
143 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
144 scr_centertime_off = scr_centertime.value;
145 scr_centertime_start = cl.time;
147 // count the number of lines for centering
148 scr_center_lines = 1;
158 void SCR_DrawCenterString (void)
165 // the finale prints the characters one at a time
167 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
171 scr_erase_center = 0;
172 start = scr_centerstring;
174 if (scr_center_lines <= 4)
181 // scan the width of the line
182 for (l=0 ; l<40 ; l++)
183 if (start[l] == '\n' || !start[l])
185 x = (vid.width - l*8)/2;
186 // LordHavoc: speedup
191 Draw_String(x, y, start, l);
197 for (j=0 ; j<l ; j++, x+=8)
199 Draw_Character (x, y, start[j]);
207 while (*start && *start != '\n')
212 start++; // skip the \n
216 void SCR_CheckDrawCenterString (void)
219 if (scr_center_lines > scr_erase_lines)
220 scr_erase_lines = scr_center_lines;
222 scr_centertime_off -= host_frametime;
224 if (scr_centertime_off <= 0 && !cl.intermission)
226 if (key_dest != key_game)
229 SCR_DrawCenterString ();
232 //=============================================================================
239 float CalcFov (float fov_x, float width, float height)
244 if (fov_x < 1 || fov_x > 179)
245 Sys_Error ("Bad fov: %f", fov_x);
247 x = width/tan(fov_x/360*M_PI);
260 Must be called whenever vid changes
264 static void SCR_CalcRefdef (void)
268 qboolean full = false;
271 scr_fullupdate = 0; // force a background redraw
272 vid.recalc_refdef = 0;
274 // force the status bar to redraw
277 //========================================
280 if (scr_viewsize.value < 30)
281 Cvar_Set ("viewsize","30");
282 if (scr_viewsize.value > 120)
283 Cvar_Set ("viewsize","120");
285 // bound field of view
286 if (scr_fov.value < 10)
287 Cvar_Set ("fov","10");
288 if (scr_fov.value > 170)
289 Cvar_Set ("fov","170");
291 // intermission is always full screen
295 size = scr_viewsize.value;
298 sb_lines = 0; // no status bar at all
299 else if (size >= 110)
300 sb_lines = 24; // no inventory
304 if (scr_viewsize.value >= 100.0)
310 size = scr_viewsize.value;
319 // LordHavoc: always fullyscreen rendering
320 h = vid.height/* - sb_lines*/;
322 r_refdef.vrect.width = vid.width * size;
323 if (r_refdef.vrect.width < 96)
325 size = 96.0 / r_refdef.vrect.width;
326 r_refdef.vrect.width = 96; // min for icons
329 r_refdef.vrect.height = vid.height * size;
330 //if (r_refdef.vrect.height > vid.height - sb_lines)
331 // r_refdef.vrect.height = vid.height - sb_lines;
332 if (r_refdef.vrect.height > (int) vid.height)
333 r_refdef.vrect.height = vid.height;
334 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
336 r_refdef.vrect.y = 0;
338 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
340 r_refdef.fov_x = scr_fov.value;
341 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
343 scr_vrect = r_refdef.vrect;
354 void SCR_SizeUp_f (void)
356 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
357 vid.recalc_refdef = 1;
368 void SCR_SizeDown_f (void)
370 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
371 vid.recalc_refdef = 1;
374 //============================================================================
384 Cvar_RegisterVariable (&scr_fov);
385 Cvar_RegisterVariable (&scr_viewsize);
386 Cvar_RegisterVariable (&scr_conspeed);
387 Cvar_RegisterVariable (&scr_showram);
388 Cvar_RegisterVariable (&scr_showturtle);
389 Cvar_RegisterVariable (&scr_showpause);
390 Cvar_RegisterVariable (&scr_centertime);
391 Cvar_RegisterVariable (&scr_printspeed);
392 Cvar_RegisterVariable (&gl_triplebuffer);
395 // register our commands
397 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
398 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
399 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
401 scr_ram = Draw_PicFromWad ("ram");
402 scr_net = Draw_PicFromWad ("net");
403 scr_turtle = Draw_PicFromWad ("turtle");
405 scr_initialized = true;
415 void SCR_DrawRam (void)
417 if (!scr_showram.value)
423 Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);
431 void SCR_DrawTurtle (void)
435 if (!scr_showturtle.value)
438 if (host_frametime < 0.1)
448 Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);
456 void SCR_DrawNet (void)
458 if (realtime - cl.last_received_message < 0.3)
460 if (cls.demoplayback)
463 Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);
471 void SCR_DrawPause (void)
475 if (!scr_showpause.value) // turn off for screenshots
481 pic = Draw_CachePic ("gfx/pause.lmp");
482 Draw_Pic ( (vid.width - pic->width)/2,
483 (vid.height - 48 - pic->height)/2, pic);
493 void SCR_DrawLoading (void)
497 if (!scr_drawloading)
500 pic = Draw_CachePic ("gfx/loading.lmp");
501 Draw_Pic ( (vid.width - pic->width)/2,
502 (vid.height - 48 - pic->height)/2, pic);
507 //=============================================================================
512 SCR_SetUpToDrawConsole
515 void SCR_SetUpToDrawConsole (void)
519 //if (scr_drawloading)
520 // return; // never a console with loading plaque
522 // decide on the height of the console
523 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
527 scr_conlines = vid.height; // full screen
528 scr_con_current = scr_conlines;
530 else if (key_dest == key_console)
531 scr_conlines = vid.height/2; // half screen
533 scr_conlines = 0; // none visible
535 if (scr_conlines < scr_con_current)
537 scr_con_current -= scr_conspeed.value*host_frametime;
538 if (scr_conlines > scr_con_current)
539 scr_con_current = scr_conlines;
542 else if (scr_conlines > scr_con_current)
544 scr_con_current += scr_conspeed.value*host_frametime;
545 if (scr_conlines < scr_con_current)
546 scr_con_current = scr_conlines;
550 if (clearconsole++ < vid.numpages)
554 else if (clearnotify++ < vid.numpages)
567 void SCR_DrawConsole (void)
571 scr_copyeverything = 1;
572 Con_DrawConsole (scr_con_current, true);
577 if (key_dest == key_game || key_dest == key_message)
578 Con_DrawNotify (); // only draw notify in game
584 ==============================================================================
588 ==============================================================================
591 typedef struct _TargaHeader {
592 unsigned char id_length, colormap_type, image_type;
593 unsigned short colormap_index, colormap_length;
594 unsigned char colormap_size;
595 unsigned short x_origin, y_origin, width, height;
596 unsigned char pixel_size, attributes;
605 void SCR_ScreenShot_f (void)
609 char checkname[MAX_OSPATH];
612 // find a file name to save it to
614 strcpy(pcxname,"dp0000.tga");
616 for (i=0 ; i<=9999 ; i++)
618 pcxname[2] = (i/1000)%10 + '0';
619 pcxname[3] = (i/ 100)%10 + '0';
620 pcxname[4] = (i/ 10)%10 + '0';
621 pcxname[5] = (i/ 1)%10 + '0';
622 sprintf (checkname, "%s/%s", com_gamedir, pcxname);
623 if (Sys_FileTime(checkname) == -1)
624 break; // file doesn't exist
628 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
633 buffer = malloc(glwidth*glheight*3 + 18);
634 memset (buffer, 0, 18);
635 buffer[2] = 2; // uncompressed type
636 buffer[12] = glwidth&255;
637 buffer[13] = glwidth>>8;
638 buffer[14] = glheight&255;
639 buffer[15] = glheight>>8;
640 buffer[16] = 24; // pixel size
642 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
645 c = 18+glwidth*glheight*3;
646 for (i=18 ; i<c ; i+=3)
649 buffer[i] = buffer[i+2];
652 COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
655 Con_Printf ("Wrote %s\n", pcxname);
659 //=============================================================================
664 SCR_BeginLoadingPlaque
668 void SCR_BeginLoadingPlaque (void)
670 S_StopAllSounds (true);
672 if (cls.state != ca_connected)
674 if (cls.signon != SIGNONS)
677 // redraw with no console and the loading plaque
679 scr_centertime_off = 0;
682 scr_drawloading = true;
686 scr_drawloading = false;
688 scr_disabled_for_loading = true;
689 scr_disabled_time = realtime;
699 void SCR_EndLoadingPlaque (void)
701 scr_disabled_for_loading = false;
706 //=============================================================================
708 char *scr_notifystring;
709 qboolean scr_drawdialog;
711 void SCR_DrawNotifyString (void)
717 start = scr_notifystring;
723 // scan the width of the line
724 for (l=0 ; l<40 ; l++)
725 if (start[l] == '\n' || !start[l])
727 x = (vid.width - l*8)/2;
728 // LordHavoc: speedup
729 // for (j=0 ; j<l ; j++, x+=8)
730 // Draw_Character (x, y, start[j]);
731 Draw_String (x, y, start, l);
735 while (*start && *start != '\n')
740 start++; // skip the \n
748 Displays a text string in the center of the screen and waits for a Y or N
752 int SCR_ModalMessage (char *text)
754 if (cls.state == ca_dedicated)
757 scr_notifystring = text;
759 // draw a fresh screen
761 scr_drawdialog = true;
763 scr_drawdialog = false;
765 S_ClearBuffer (); // so dma doesn't loop current sound
769 key_count = -1; // wait for a key down and up
770 Sys_SendKeyEvents ();
771 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
776 return key_lastpress == 'y';
780 //=============================================================================
786 Brings the console down and fades the palettes back to normal
789 void SCR_BringDownConsole (void)
793 scr_centertime_off = 0;
795 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
798 cl.cshifts[0].percent = 0; // no area contents palette on next frame
799 VID_SetPalette (host_basepal);
802 void GL_Set2D (void);
804 extern void SHOWLMP_drawall();
805 extern cvar_t contrast;
806 extern cvar_t brightness;
807 extern cvar_t gl_lightmode;
809 void GL_BrightenScreen()
812 glDisable(GL_TEXTURE_2D);
814 f = brightness.value = bound(1.0f, brightness.value, 5.0f);
817 glBlendFunc (GL_DST_COLOR, GL_ONE);
818 glBegin (GL_TRIANGLES);
824 glColor3f (f-1, f-1, f-1);
825 glVertex2f (-5000, -5000);
826 glVertex2f (10000, -5000);
827 glVertex2f (-5000, 10000);
832 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
833 contrast.value = bound(0.2, contrast.value, 1.0);
834 if (contrast.value < 1.0f)
836 glBegin (GL_TRIANGLES);
837 glColor4f (1, 1, 1, 1-contrast.value);
838 glVertex2f (-5000, -5000);
839 glVertex2f (10000, -5000);
840 glVertex2f (-5000, 10000);
844 glEnable (GL_CULL_FACE);
845 glEnable (GL_DEPTH_TEST);
847 glEnable(GL_TEXTURE_2D);
854 This is called every frame, and can also be called explicitly to flush
857 WARNING: be very careful calling this from elsewhere, because the refresh
858 needs almost the entire 256k of stack space!
861 extern cvar_t gl_vertexarrays;
862 extern qboolean gl_arrays;
865 void SCR_UpdateScreen (void)
867 static float oldscr_viewsize;
872 time1 = Sys_FloatTime ();
879 gl_vertexarrays.value = 0;
881 vid.numpages = 2 + gl_triplebuffer.value;
884 scr_copyeverything = 0;
886 if (scr_disabled_for_loading)
888 if (realtime - scr_disabled_time > 60)
890 scr_disabled_for_loading = false;
891 Con_Printf ("load failed.\n");
897 if (!scr_initialized || !con_initialized)
898 return; // not initialized yet
901 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
904 // determine size of refresh window
906 if (oldfov != scr_fov.value)
908 oldfov = scr_fov.value;
909 vid.recalc_refdef = true;
912 if (oldscreensize != scr_viewsize.value)
914 oldscreensize = scr_viewsize.value;
915 vid.recalc_refdef = true;
918 if (vid.recalc_refdef)
921 glClearColor(0,0,0,0);
922 glClear (GL_COLOR_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
925 // do 3D refresh drawing, and then update the screen
927 SCR_SetUpToDrawConsole ();
936 // Draw_FadeScreen ();
937 SCR_DrawNotifyString ();
938 scr_copyeverything = true;
940 else if (scr_drawloading)
945 else if (cl.intermission == 1 && key_dest == key_game)
947 Sbar_IntermissionOverlay ();
949 else if (cl.intermission == 2 && key_dest == key_game)
951 Sbar_FinaleOverlay ();
952 SCR_CheckDrawCenterString ();
957 Draw_Character (scr_vrect.x + scr_vrect.width/2, scr_vrect.y + scr_vrect.height/2, '+');
963 SCR_CheckDrawCenterString ();
978 time2 = Sys_FloatTime ();
979 Con_Printf ("%3i ms %4i wpoly %4i epoly %4i BSPnodes\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, c_nodes);
984 // for profiling, this is seperated