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 always rendered, unless the console is full screen
73 int glx, gly, glwidth, glheight;
75 float scr_con_current;
76 float scr_conlines; // lines of console to display
78 float oldscreensize, oldfov;
79 cvar_t scr_viewsize = {"viewsize","100", true};
80 cvar_t scr_fov = {"fov","90"}; // 10 - 170
81 cvar_t scr_conspeed = {"scr_conspeed","300"};
82 cvar_t scr_centertime = {"scr_centertime","2"};
83 cvar_t scr_showram = {"showram","1"};
84 cvar_t scr_showturtle = {"showturtle","0"};
85 cvar_t scr_showpause = {"showpause","1"};
86 cvar_t scr_printspeed = {"scr_printspeed","8"};
87 cvar_t showfps = {"showfps", "0", true};
88 cvar_t r_render = {"r_render", "1"};
89 cvar_t r_brightness = {"r_brightness", "1", true}; // LordHavoc: a method of operating system independent color correction
90 cvar_t r_contrast = {"r_contrast", "1", true}; // LordHavoc: a method of operating system independent color correction
92 qboolean scr_initialized; // ready to draw
101 qboolean scr_disabled_for_loading;
102 //qboolean scr_drawloading;
103 //float scr_disabled_time;
105 void SCR_ScreenShot_f (void);
108 ===============================================================================
112 ===============================================================================
115 char scr_centerstring[1024];
116 float scr_centertime_start; // for slow victory printing
117 float scr_centertime_off;
118 int scr_center_lines;
120 int scr_erase_center;
126 Called for important messages that should stay in the center of the screen
130 void SCR_CenterPrint (char *str)
132 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
133 scr_centertime_off = scr_centertime.value;
134 scr_centertime_start = cl.time;
136 // count the number of lines for centering
137 scr_center_lines = 1;
147 void SCR_DrawCenterString (void)
154 // the finale prints the characters one at a time
156 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
160 scr_erase_center = 0;
161 start = scr_centerstring;
163 if (scr_center_lines <= 4)
170 // scan the width of the line
171 for (l=0 ; l<40 ; l++)
172 if (start[l] == '\n' || !start[l])
174 x = (vid.width - l*8)/2;
175 // LordHavoc: speedup
180 Draw_String(x, y, start, l);
186 for (j=0 ; j<l ; j++, x+=8)
188 Draw_Character (x, y, start[j]);
196 while (*start && *start != '\n')
201 start++; // skip the \n
205 void SCR_CheckDrawCenterString (void)
207 if (scr_center_lines > scr_erase_lines)
208 scr_erase_lines = scr_center_lines;
210 scr_centertime_off -= host_frametime;
212 if (scr_centertime_off <= 0 && !cl.intermission)
214 if (key_dest != key_game)
217 SCR_DrawCenterString ();
220 //=============================================================================
227 float CalcFov (float fov_x, float width, float height)
232 if (fov_x < 1 || fov_x > 179)
233 Sys_Error ("Bad fov: %f", fov_x);
235 x = width/tan(fov_x/360*M_PI);
248 Must be called whenever vid changes
252 static void SCR_CalcRefdef (void)
256 qboolean full = false;
259 vid.recalc_refdef = 0;
261 //========================================
264 if (scr_viewsize.value < 30)
265 Cvar_Set ("viewsize","30");
266 if (scr_viewsize.value > 120)
267 Cvar_Set ("viewsize","120");
269 // bound field of view
270 if (scr_fov.value < 10)
271 Cvar_Set ("fov","10");
272 if (scr_fov.value > 170)
273 Cvar_Set ("fov","170");
275 // intermission is always full screen
284 if (scr_viewsize.value >= 120)
285 sb_lines = 0; // no status bar at all
286 else if (scr_viewsize.value >= 110)
287 sb_lines = 24; // no inventory
291 if (scr_viewsize.value >= 100.0)
297 size = scr_viewsize.value * (1.0f / 100.0f);
300 // LordHavoc: always fullscreen rendering
301 h = vid.height/* - sb_lines*/;
303 r_refdef.vrect.width = vid.width * size;
304 if (r_refdef.vrect.width < 96)
306 size = 96.0 / r_refdef.vrect.width;
307 r_refdef.vrect.width = 96; // min for icons
310 r_refdef.vrect.height = vid.height * size;
311 //if (r_refdef.vrect.height > vid.height - sb_lines)
312 // r_refdef.vrect.height = vid.height - sb_lines;
313 if (r_refdef.vrect.height > (int) vid.height)
314 r_refdef.vrect.height = vid.height;
315 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
317 r_refdef.vrect.y = 0;
319 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
321 r_refdef.fov_x = scr_fov.value;
322 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
333 void SCR_SizeUp_f (void)
335 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
336 vid.recalc_refdef = 1;
347 void SCR_SizeDown_f (void)
349 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
350 vid.recalc_refdef = 1;
353 //============================================================================
355 void gl_screen_start(void)
357 scr_ram = Draw_PicFromWad ("ram");
358 scr_net = Draw_PicFromWad ("net");
359 scr_turtle = Draw_PicFromWad ("turtle");
362 void gl_screen_shutdown(void)
366 void gl_screen_newmap(void)
375 void GL_Screen_Init (void)
378 Cvar_RegisterVariable (&scr_fov);
379 Cvar_RegisterVariable (&scr_viewsize);
380 Cvar_RegisterVariable (&scr_conspeed);
381 Cvar_RegisterVariable (&scr_showram);
382 Cvar_RegisterVariable (&scr_showturtle);
383 Cvar_RegisterVariable (&scr_showpause);
384 Cvar_RegisterVariable (&scr_centertime);
385 Cvar_RegisterVariable (&scr_printspeed);
386 Cvar_RegisterVariable (&showfps);
387 Cvar_RegisterVariable (&r_render);
388 Cvar_RegisterVariable (&r_brightness);
389 Cvar_RegisterVariable (&r_contrast);
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_initialized = true;
403 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
413 void SCR_DrawRam (void)
415 if (!scr_showram.value)
421 Draw_Pic (32, 0, scr_ram);
429 void SCR_DrawTurtle (void)
433 if (!scr_showturtle.value)
436 if (cl.frametime < 0.1)
446 Draw_Pic (0, 0, scr_turtle);
454 void SCR_DrawNet (void)
456 if (realtime - cl.last_received_message < 0.3)
458 if (cls.demoplayback)
461 Draw_Pic (64, 0, scr_net);
469 void SCR_DrawPause (void)
473 if (!scr_showpause.value) // turn off for screenshots
479 pic = Draw_CachePic ("gfx/pause.lmp");
480 Draw_Pic ( (vid.width - pic->width)/2,
481 (vid.height - 48 - pic->height)/2, pic);
492 void SCR_DrawLoading (void)
496 if (!scr_drawloading)
499 pic = Draw_CachePic ("gfx/loading.lmp");
500 Draw_Pic ( (vid.width - pic->width)/2,
501 (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_realframetime;
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_realframetime;
545 if (scr_conlines < scr_con_current)
546 scr_con_current = scr_conlines;
555 void SCR_DrawConsole (void)
559 Con_DrawConsole (scr_con_current, true);
564 if (key_dest == key_game || key_dest == key_message)
565 Con_DrawNotify (); // only draw notify in game
571 ==============================================================================
575 ==============================================================================
583 void SCR_ScreenShot_f (void)
587 char checkname[MAX_OSPATH];
590 // find a file name to save it to
592 strcpy(filename,"dp0000.tga");
594 for (i=0 ; i<=9999 ; i++)
596 filename[2] = (i/1000)%10 + '0';
597 filename[3] = (i/ 100)%10 + '0';
598 filename[4] = (i/ 10)%10 + '0';
599 filename[5] = (i/ 1)%10 + '0';
600 sprintf (checkname, "%s/%s", com_gamedir, filename);
601 if (Sys_FileTime(checkname) == -1)
602 break; // file doesn't exist
606 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
610 buffer = qmalloc(glwidth*glheight*3);
611 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
612 Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
615 Con_Printf ("Wrote %s\n", filename);
619 //=============================================================================
624 SCR_BeginLoadingPlaque
629 void SCR_BeginLoadingPlaque (void)
631 S_StopAllSounds (true);
633 // if (cls.state != ca_connected)
635 // if (cls.signon != SIGNONS)
638 // redraw with no console and the loading plaque
639 // Con_ClearNotify ();
640 // scr_centertime_off = 0;
641 // scr_con_current = 0;
643 scr_drawloading = true;
646 // scr_disabled_for_loading = true;
647 // scr_disabled_time = realtime;
658 void SCR_EndLoadingPlaque (void)
660 // scr_disabled_for_loading = false;
661 scr_drawloading = false;
666 //=============================================================================
668 char *scr_notifystring;
670 void SCR_DrawNotifyString (void)
676 start = scr_notifystring;
682 // scan the width of the line
683 for (l=0 ; l<40 ; l++)
684 if (start[l] == '\n' || !start[l])
686 x = (vid.width - l*8)/2;
687 // LordHavoc: speedup
688 // for (j=0 ; j<l ; j++, x+=8)
689 // Draw_Character (x, y, start[j]);
690 Draw_String (x, y, start, l);
694 while (*start && *start != '\n')
699 start++; // skip the \n
703 //=============================================================================
705 void DrawCrosshair(int num);
706 void GL_Set2D (void);
708 void GL_BrightenScreen(void)
712 if (r_brightness.value < 0.1f)
713 Cvar_SetValue("r_brightness", 0.1f);
714 if (r_brightness.value > 5.0f)
715 Cvar_SetValue("r_brightness", 5.0f);
717 if (r_contrast.value < 0.2f)
718 Cvar_SetValue("r_contrast", 0.2f);
719 if (r_contrast.value > 1.0f)
720 Cvar_SetValue("r_contrast", 1.0f);
722 if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
728 glDisable(GL_TEXTURE_2D);
730 f = r_brightness.value;
731 // only apply lighthalf using software color correction if hardware is not available (speed reasons)
732 if (lighthalf && !hardwaregammasupported)
736 glBlendFunc (GL_DST_COLOR, GL_ONE);
737 glBegin (GL_TRIANGLES);
743 glColor3f (f-1, f-1, f-1);
744 glVertex2f (-5000, -5000);
745 glVertex2f (10000, -5000);
746 glVertex2f (-5000, 10000);
751 if (r_contrast.value <= 0.99f)
753 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
754 if (lighthalf && hardwaregammasupported)
755 glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
757 glColor4f (1, 1, 1, 1 - r_contrast.value);
758 glBegin (GL_TRIANGLES);
759 glVertex2f (-5000, -5000);
760 glVertex2f (10000, -5000);
761 glVertex2f (-5000, 10000);
764 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
766 glEnable (GL_CULL_FACE);
767 glEnable (GL_DEPTH_TEST);
769 glEnable(GL_TEXTURE_2D);
776 This is called every frame, and can also be called explicitly to flush
779 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
782 void GL_Finish(void);
783 void R_Clip_DisplayBuffer(void);
784 void SCR_UpdateScreen (void)
786 double time1 = 0, time2;
789 time1 = Sys_DoubleTime ();
791 VID_UpdateGamma(false);
793 if (scr_disabled_for_loading)
796 if (realtime - scr_disabled_time > 60)
798 scr_disabled_for_loading = false;
799 Con_Printf ("load failed.\n");
806 if (!scr_initialized || !con_initialized)
807 return; // not initialized yet
810 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
813 // determine size of refresh window
815 if (oldfov != scr_fov.value)
817 oldfov = scr_fov.value;
818 vid.recalc_refdef = true;
821 if (oldscreensize != scr_viewsize.value)
823 oldscreensize = scr_viewsize.value;
824 vid.recalc_refdef = true;
827 if (vid.recalc_refdef)
832 glClearColor(0,0,0,0);
833 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
837 // do 3D refresh drawing, and then update the screen
839 SCR_SetUpToDrawConsole();
845 R_Clip_DisplayBuffer();
851 SCR_CheckDrawCenterString();
856 DrawCrosshair(crosshair.value - 1);
858 if (cl.intermission == 1)
859 Sbar_IntermissionOverlay();
860 else if (cl.intermission == 2)
861 Sbar_FinaleOverlay();
866 // if (scr_drawloading)
867 // SCR_DrawLoading();
871 static double currtime;
875 newtime = Sys_DoubleTime();
876 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
877 sprintf(temp, "%4i fps", calc);
879 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
882 // LordHavoc: only print info if renderer is being used
883 if (r_speeds2.value && cl.worldmodel != NULL)
887 for (i = 0;r_speeds2_string[i];i++)
888 if (r_speeds2_string[i] == '\n')
890 y = vid.height - sb_lines - lines * 8 - 8;
892 while (r_speeds2_string[i])
895 while (r_speeds2_string[i] && r_speeds2_string[i] != '\n')
898 Draw_String(0, y, r_speeds2_string + j, i - j);
899 if (r_speeds2_string[i] == '\n')
913 time2 = Sys_DoubleTime ();
914 Con_Printf ("%3i ms %4i wpoly %4i epoly %4i transpoly %4i lightpoly %4i BSPnodes %4i BSPleafs %4i BSPfaces %4i models %4i bmodels %4i sprites %4i particles %3i dlights\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys, currenttranspoly, c_light_polys, c_nodes, c_leafs, c_faces, c_models, c_bmodels, c_sprites, c_particles, c_dlights);
919 // for profiling, this is separated