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 showfps = {"showfps", "0", true};
93 extern cvar_t crosshair;
95 qboolean scr_initialized; // ready to draw
108 extern viddef_t vid; // global video state
110 qboolean scr_disabled_for_loading;
111 qboolean scr_drawloading;
112 float scr_disabled_time;
114 void SCR_ScreenShot_f (void);
117 ===============================================================================
121 ===============================================================================
124 char scr_centerstring[1024];
125 float scr_centertime_start; // for slow victory printing
126 float scr_centertime_off;
127 int scr_center_lines;
129 int scr_erase_center;
135 Called for important messages that should stay in the center of the screen
139 void SCR_CenterPrint (char *str)
141 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
142 scr_centertime_off = scr_centertime.value;
143 scr_centertime_start = cl.time;
145 // count the number of lines for centering
146 scr_center_lines = 1;
156 void SCR_DrawCenterString (void)
163 // the finale prints the characters one at a time
165 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
169 scr_erase_center = 0;
170 start = scr_centerstring;
172 if (scr_center_lines <= 4)
179 // scan the width of the line
180 for (l=0 ; l<40 ; l++)
181 if (start[l] == '\n' || !start[l])
183 x = (vid.width - l*8)/2;
184 // LordHavoc: speedup
189 Draw_String(x, y, start, l);
195 for (j=0 ; j<l ; j++, x+=8)
197 Draw_Character (x, y, start[j]);
205 while (*start && *start != '\n')
210 start++; // skip the \n
214 void SCR_CheckDrawCenterString (void)
217 if (scr_center_lines > scr_erase_lines)
218 scr_erase_lines = scr_center_lines;
220 scr_centertime_off -= host_frametime;
222 if (scr_centertime_off <= 0 && !cl.intermission)
224 if (key_dest != key_game)
227 SCR_DrawCenterString ();
230 //=============================================================================
237 float CalcFov (float fov_x, float width, float height)
242 if (fov_x < 1 || fov_x > 179)
243 Sys_Error ("Bad fov: %f", fov_x);
245 x = width/tan(fov_x/360*M_PI);
258 Must be called whenever vid changes
262 static void SCR_CalcRefdef (void)
266 qboolean full = false;
269 scr_fullupdate = 0; // force a background redraw
270 vid.recalc_refdef = 0;
272 // force the status bar to redraw
275 //========================================
278 if (scr_viewsize.value < 30)
279 Cvar_Set ("viewsize","30");
280 if (scr_viewsize.value > 120)
281 Cvar_Set ("viewsize","120");
283 // bound field of view
284 if (scr_fov.value < 10)
285 Cvar_Set ("fov","10");
286 if (scr_fov.value > 170)
287 Cvar_Set ("fov","170");
289 // intermission is always full screen
293 size = scr_viewsize.value;
296 sb_lines = 0; // no status bar at all
297 else if (size >= 110)
298 sb_lines = 24; // no inventory
302 if (scr_viewsize.value >= 100.0)
308 size = scr_viewsize.value;
317 // LordHavoc: always fullyscreen rendering
318 h = vid.height/* - sb_lines*/;
320 r_refdef.vrect.width = vid.width * size;
321 if (r_refdef.vrect.width < 96)
323 size = 96.0 / r_refdef.vrect.width;
324 r_refdef.vrect.width = 96; // min for icons
327 r_refdef.vrect.height = vid.height * size;
328 //if (r_refdef.vrect.height > vid.height - sb_lines)
329 // r_refdef.vrect.height = vid.height - sb_lines;
330 if (r_refdef.vrect.height > (int) vid.height)
331 r_refdef.vrect.height = vid.height;
332 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
334 r_refdef.vrect.y = 0;
336 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
338 r_refdef.fov_x = scr_fov.value;
339 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
350 void SCR_SizeUp_f (void)
352 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
353 vid.recalc_refdef = 1;
364 void SCR_SizeDown_f (void)
366 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
367 vid.recalc_refdef = 1;
370 //============================================================================
380 Cvar_RegisterVariable (&scr_fov);
381 Cvar_RegisterVariable (&scr_viewsize);
382 Cvar_RegisterVariable (&scr_conspeed);
383 Cvar_RegisterVariable (&scr_showram);
384 Cvar_RegisterVariable (&scr_showturtle);
385 Cvar_RegisterVariable (&scr_showpause);
386 Cvar_RegisterVariable (&scr_centertime);
387 Cvar_RegisterVariable (&scr_printspeed);
388 Cvar_RegisterVariable (&showfps);
391 // register our commands
393 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
394 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
395 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
397 scr_ram = Draw_PicFromWad ("ram");
398 scr_net = Draw_PicFromWad ("net");
399 scr_turtle = Draw_PicFromWad ("turtle");
401 scr_initialized = true;
411 void SCR_DrawRam (void)
413 if (!scr_showram.value)
419 Draw_Pic (32, 0, scr_ram);
427 void SCR_DrawTurtle (void)
431 if (!scr_showturtle.value)
434 if (host_frametime < 0.1)
444 Draw_Pic (0, 0, scr_turtle);
452 void SCR_DrawNet (void)
454 if (realtime - cl.last_received_message < 0.3)
456 if (cls.demoplayback)
459 Draw_Pic (64, 0, scr_net);
467 void SCR_DrawPause (void)
471 if (!scr_showpause.value) // turn off for screenshots
477 pic = Draw_CachePic ("gfx/pause.lmp");
478 Draw_Pic ( (vid.width - pic->width)/2,
479 (vid.height - 48 - pic->height)/2, pic);
489 void SCR_DrawLoading (void)
493 if (!scr_drawloading)
496 pic = Draw_CachePic ("gfx/loading.lmp");
497 Draw_Pic ( (vid.width - pic->width)/2,
498 (vid.height - 48 - pic->height)/2, pic);
503 //=============================================================================
508 SCR_SetUpToDrawConsole
511 void SCR_SetUpToDrawConsole (void)
515 //if (scr_drawloading)
516 // return; // never a console with loading plaque
518 // decide on the height of the console
519 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
523 scr_conlines = vid.height; // full screen
524 scr_con_current = scr_conlines;
526 else if (key_dest == key_console)
527 scr_conlines = vid.height/2; // half screen
529 scr_conlines = 0; // none visible
531 if (scr_conlines < scr_con_current)
533 scr_con_current -= scr_conspeed.value*host_frametime;
534 if (scr_conlines > scr_con_current)
535 scr_con_current = scr_conlines;
538 else if (scr_conlines > scr_con_current)
540 scr_con_current += scr_conspeed.value*host_frametime;
541 if (scr_conlines < scr_con_current)
542 scr_con_current = scr_conlines;
551 void SCR_DrawConsole (void)
555 scr_copyeverything = 1;
556 Con_DrawConsole (scr_con_current, true);
561 if (key_dest == key_game || key_dest == key_message)
562 Con_DrawNotify (); // only draw notify in game
568 ==============================================================================
572 ==============================================================================
575 typedef struct _TargaHeader {
576 unsigned char id_length, colormap_type, image_type;
577 unsigned short colormap_index, colormap_length;
578 unsigned char colormap_size;
579 unsigned short x_origin, y_origin, width, height;
580 unsigned char pixel_size, attributes;
589 void SCR_ScreenShot_f (void)
593 char checkname[MAX_OSPATH];
596 // find a file name to save it to
598 strcpy(pcxname,"dp0000.tga");
600 for (i=0 ; i<=9999 ; i++)
602 pcxname[2] = (i/1000)%10 + '0';
603 pcxname[3] = (i/ 100)%10 + '0';
604 pcxname[4] = (i/ 10)%10 + '0';
605 pcxname[5] = (i/ 1)%10 + '0';
606 sprintf (checkname, "%s/%s", com_gamedir, pcxname);
607 if (Sys_FileTime(checkname) == -1)
608 break; // file doesn't exist
612 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
617 buffer = malloc(glwidth*glheight*3 + 18);
618 memset (buffer, 0, 18);
619 buffer[2] = 2; // uncompressed type
620 buffer[12] = glwidth&255;
621 buffer[13] = glwidth>>8;
622 buffer[14] = glheight&255;
623 buffer[15] = glheight>>8;
624 buffer[16] = 24; // pixel size
626 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
629 c = 18+glwidth*glheight*3;
630 for (i=18 ; i<c ; i+=3)
633 buffer[i] = buffer[i+2];
636 COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
639 Con_Printf ("Wrote %s\n", pcxname);
643 //=============================================================================
648 SCR_BeginLoadingPlaque
652 void SCR_BeginLoadingPlaque (void)
654 S_StopAllSounds (true);
656 if (cls.state != ca_connected)
658 if (cls.signon != SIGNONS)
661 // redraw with no console and the loading plaque
663 scr_centertime_off = 0;
666 scr_drawloading = true;
670 scr_drawloading = false;
672 scr_disabled_for_loading = true;
673 scr_disabled_time = realtime;
683 void SCR_EndLoadingPlaque (void)
685 scr_disabled_for_loading = false;
690 //=============================================================================
692 char *scr_notifystring;
693 qboolean scr_drawdialog;
695 void SCR_DrawNotifyString (void)
701 start = scr_notifystring;
707 // scan the width of the line
708 for (l=0 ; l<40 ; l++)
709 if (start[l] == '\n' || !start[l])
711 x = (vid.width - l*8)/2;
712 // LordHavoc: speedup
713 // for (j=0 ; j<l ; j++, x+=8)
714 // Draw_Character (x, y, start[j]);
715 Draw_String (x, y, start, l);
719 while (*start && *start != '\n')
724 start++; // skip the \n
732 Displays a text string in the center of the screen and waits for a Y or N
736 int SCR_ModalMessage (char *text)
738 if (cls.state == ca_dedicated)
741 scr_notifystring = text;
743 // draw a fresh screen
745 scr_drawdialog = true;
747 scr_drawdialog = false;
749 S_ClearBuffer (); // so dma doesn't loop current sound
753 key_count = -1; // wait for a key down and up
754 Sys_SendKeyEvents ();
755 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
760 return key_lastpress == 'y';
764 //=============================================================================
770 Brings the console down and fades the palettes back to normal
773 void SCR_BringDownConsole (void)
777 scr_centertime_off = 0;
779 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
782 cl.cshifts[0].percent = 0; // no area contents palette on next frame
783 VID_SetPalette (host_basepal);
786 void GL_Set2D (void);
788 extern void SHOWLMP_drawall();
789 extern cvar_t contrast;
790 extern cvar_t brightness;
791 extern cvar_t gl_lightmode;
793 void GL_BrightenScreen()
796 glDisable(GL_TEXTURE_2D);
798 f = brightness.value = bound(1.0f, brightness.value, 5.0f);
801 glBlendFunc (GL_DST_COLOR, GL_ONE);
802 glBegin (GL_TRIANGLES);
808 glColor3f (f-1, f-1, f-1);
809 glVertex2f (-5000, -5000);
810 glVertex2f (10000, -5000);
811 glVertex2f (-5000, 10000);
816 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
817 contrast.value = bound(0.2, contrast.value, 1.0);
818 if (contrast.value < 0.99f)
820 glBegin (GL_TRIANGLES);
821 glColor4f (1, 1, 1, 1-contrast.value);
822 glVertex2f (-5000, -5000);
823 glVertex2f (10000, -5000);
824 glVertex2f (-5000, 10000);
828 glEnable (GL_CULL_FACE);
829 glEnable (GL_DEPTH_TEST);
831 glEnable(GL_TEXTURE_2D);
838 This is called every frame, and can also be called explicitly to flush
841 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
844 extern cvar_t gl_vertexarrays;
845 extern qboolean gl_arrays;
847 void SCR_UpdateScreen (void)
849 double time1 = 0, time2;
852 time1 = Sys_FloatTime ();
855 gl_vertexarrays.value = 0;
858 scr_copyeverything = 0;
860 if (scr_disabled_for_loading)
862 if (realtime - scr_disabled_time > 60)
864 scr_disabled_for_loading = false;
865 Con_Printf ("load failed.\n");
871 if (!scr_initialized || !con_initialized)
872 return; // not initialized yet
875 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
878 // determine size of refresh window
880 if (oldfov != scr_fov.value)
882 oldfov = scr_fov.value;
883 vid.recalc_refdef = true;
886 if (oldscreensize != scr_viewsize.value)
888 oldscreensize = scr_viewsize.value;
889 vid.recalc_refdef = true;
892 if (vid.recalc_refdef)
895 glClearColor(1,0,0,0);
896 glClear (GL_COLOR_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
899 // do 3D refresh drawing, and then update the screen
901 SCR_SetUpToDrawConsole ();
910 // Draw_FadeScreen ();
911 SCR_DrawNotifyString ();
912 scr_copyeverything = true;
914 else if (scr_drawloading)
919 else if (cl.intermission == 1 && key_dest == key_game)
921 Sbar_IntermissionOverlay ();
923 else if (cl.intermission == 2 && key_dest == key_game)
925 Sbar_FinaleOverlay ();
926 SCR_CheckDrawCenterString ();
931 Draw_Character (r_refdef.vrect.x + r_refdef.vrect.width/2, r_refdef.vrect.y + r_refdef.vrect.height/2, '+');
937 SCR_CheckDrawCenterString ();
946 static double currtime;
950 newtime = Sys_FloatTime();
951 calc = (int) (100.0 / (newtime - currtime));
952 sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
954 Draw_String(vid.width - (12*8), 0, temp, 9999);
965 time2 = Sys_FloatTime ();
966 Con_Printf ("%3i ms %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs);
971 // for profiling, this is seperated