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
279 size = scr_viewsize.value;
282 sb_lines = 0; // no status bar at all
283 else if (size >= 110)
284 sb_lines = 24; // no inventory
288 if (scr_viewsize.value >= 100.0)
294 size = scr_viewsize.value;
303 // LordHavoc: always fullyscreen rendering
304 h = vid.height/* - sb_lines*/;
306 r_refdef.vrect.width = vid.width * size;
307 if (r_refdef.vrect.width < 96)
309 size = 96.0 / r_refdef.vrect.width;
310 r_refdef.vrect.width = 96; // min for icons
313 r_refdef.vrect.height = vid.height * size;
314 //if (r_refdef.vrect.height > vid.height - sb_lines)
315 // r_refdef.vrect.height = vid.height - sb_lines;
316 if (r_refdef.vrect.height > (int) vid.height)
317 r_refdef.vrect.height = vid.height;
318 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
320 r_refdef.vrect.y = 0;
322 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
324 r_refdef.fov_x = scr_fov.value;
325 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
336 void SCR_SizeUp_f (void)
338 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
339 vid.recalc_refdef = 1;
350 void SCR_SizeDown_f (void)
352 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
353 vid.recalc_refdef = 1;
356 //============================================================================
358 void gl_screen_start(void)
360 scr_ram = Draw_PicFromWad ("ram");
361 scr_net = Draw_PicFromWad ("net");
362 scr_turtle = Draw_PicFromWad ("turtle");
365 void gl_screen_shutdown(void)
369 void gl_screen_newmap(void)
378 void GL_Screen_Init (void)
381 Cvar_RegisterVariable (&scr_fov);
382 Cvar_RegisterVariable (&scr_viewsize);
383 Cvar_RegisterVariable (&scr_conspeed);
384 Cvar_RegisterVariable (&scr_showram);
385 Cvar_RegisterVariable (&scr_showturtle);
386 Cvar_RegisterVariable (&scr_showpause);
387 Cvar_RegisterVariable (&scr_centertime);
388 Cvar_RegisterVariable (&scr_printspeed);
389 Cvar_RegisterVariable (&showfps);
390 Cvar_RegisterVariable (&r_render);
391 Cvar_RegisterVariable (&r_brightness);
392 Cvar_RegisterVariable (&r_contrast);
398 // register our commands
400 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
401 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
402 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
404 scr_initialized = true;
406 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
416 void SCR_DrawRam (void)
418 if (!scr_showram.value)
424 Draw_Pic (32, 0, scr_ram);
432 void SCR_DrawTurtle (void)
436 if (!scr_showturtle.value)
439 if (cl.frametime < 0.1)
449 Draw_Pic (0, 0, scr_turtle);
457 void SCR_DrawNet (void)
459 if (realtime - cl.last_received_message < 0.3)
461 if (cls.demoplayback)
464 Draw_Pic (64, 0, scr_net);
472 void SCR_DrawPause (void)
476 if (!scr_showpause.value) // turn off for screenshots
482 pic = Draw_CachePic ("gfx/pause.lmp");
483 Draw_Pic ( (vid.width - pic->width)/2,
484 (vid.height - 48 - pic->height)/2, pic);
495 void SCR_DrawLoading (void)
499 if (!scr_drawloading)
502 pic = Draw_CachePic ("gfx/loading.lmp");
503 Draw_Pic ( (vid.width - pic->width)/2,
504 (vid.height - 48 - pic->height)/2, pic);
510 //=============================================================================
515 SCR_SetUpToDrawConsole
518 void SCR_SetUpToDrawConsole (void)
522 //if (scr_drawloading)
523 // return; // never a console with loading plaque
525 // decide on the height of the console
526 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
530 scr_conlines = vid.height; // full screen
531 scr_con_current = scr_conlines;
533 else if (key_dest == key_console)
534 scr_conlines = vid.height/2; // half screen
536 scr_conlines = 0; // none visible
538 if (scr_conlines < scr_con_current)
540 scr_con_current -= scr_conspeed.value*host_realframetime;
541 if (scr_conlines > scr_con_current)
542 scr_con_current = scr_conlines;
545 else if (scr_conlines > scr_con_current)
547 scr_con_current += scr_conspeed.value*host_realframetime;
548 if (scr_conlines < scr_con_current)
549 scr_con_current = scr_conlines;
558 void SCR_DrawConsole (void)
562 Con_DrawConsole (scr_con_current, true);
567 if (key_dest == key_game || key_dest == key_message)
568 Con_DrawNotify (); // only draw notify in game
574 ==============================================================================
578 ==============================================================================
586 void SCR_ScreenShot_f (void)
590 char checkname[MAX_OSPATH];
593 // find a file name to save it to
595 strcpy(filename,"dp0000.tga");
597 for (i=0 ; i<=9999 ; i++)
599 filename[2] = (i/1000)%10 + '0';
600 filename[3] = (i/ 100)%10 + '0';
601 filename[4] = (i/ 10)%10 + '0';
602 filename[5] = (i/ 1)%10 + '0';
603 sprintf (checkname, "%s/%s", com_gamedir, filename);
604 if (Sys_FileTime(checkname) == -1)
605 break; // file doesn't exist
609 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
613 buffer = qmalloc(glwidth*glheight*3);
614 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
615 Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
618 Con_Printf ("Wrote %s\n", filename);
622 //=============================================================================
627 SCR_BeginLoadingPlaque
632 void SCR_BeginLoadingPlaque (void)
634 S_StopAllSounds (true);
636 // if (cls.state != ca_connected)
638 // if (cls.signon != SIGNONS)
641 // redraw with no console and the loading plaque
642 // Con_ClearNotify ();
643 // scr_centertime_off = 0;
644 // scr_con_current = 0;
646 scr_drawloading = true;
649 // scr_disabled_for_loading = true;
650 // scr_disabled_time = realtime;
661 void SCR_EndLoadingPlaque (void)
663 // scr_disabled_for_loading = false;
664 scr_drawloading = false;
669 //=============================================================================
671 char *scr_notifystring;
673 void SCR_DrawNotifyString (void)
679 start = scr_notifystring;
685 // scan the width of the line
686 for (l=0 ; l<40 ; l++)
687 if (start[l] == '\n' || !start[l])
689 x = (vid.width - l*8)/2;
690 // LordHavoc: speedup
691 // for (j=0 ; j<l ; j++, x+=8)
692 // Draw_Character (x, y, start[j]);
693 Draw_String (x, y, start, l);
697 while (*start && *start != '\n')
702 start++; // skip the \n
706 //=============================================================================
708 void DrawCrosshair(int num);
709 void GL_Set2D (void);
711 void GL_BrightenScreen(void)
715 if (r_brightness.value < 0.1f)
716 Cvar_SetValue("r_brightness", 0.1f);
717 if (r_brightness.value > 5.0f)
718 Cvar_SetValue("r_brightness", 5.0f);
720 if (r_contrast.value < 0.2f)
721 Cvar_SetValue("r_contrast", 0.2f);
722 if (r_contrast.value > 1.0f)
723 Cvar_SetValue("r_contrast", 1.0f);
725 if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
731 glDisable(GL_TEXTURE_2D);
733 f = r_brightness.value;
734 // only apply lighthalf using software color correction if hardware is not available (speed reasons)
735 if (lighthalf && !hardwaregammasupported)
739 glBlendFunc (GL_DST_COLOR, GL_ONE);
740 glBegin (GL_TRIANGLES);
746 glColor3f (f-1, f-1, f-1);
747 glVertex2f (-5000, -5000);
748 glVertex2f (10000, -5000);
749 glVertex2f (-5000, 10000);
754 if (r_contrast.value <= 0.99f)
756 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
757 if (lighthalf && hardwaregammasupported)
758 glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
760 glColor4f (1, 1, 1, 1 - r_contrast.value);
761 glBegin (GL_TRIANGLES);
762 glVertex2f (-5000, -5000);
763 glVertex2f (10000, -5000);
764 glVertex2f (-5000, 10000);
767 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
769 glEnable (GL_CULL_FACE);
770 glEnable (GL_DEPTH_TEST);
772 glEnable(GL_TEXTURE_2D);
779 This is called every frame, and can also be called explicitly to flush
782 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
785 void GL_Finish(void);
786 void SCR_UpdateScreen (void)
788 double time1 = 0, time2;
791 time1 = Sys_DoubleTime ();
793 VID_UpdateGamma(false);
795 if (scr_disabled_for_loading)
798 if (realtime - scr_disabled_time > 60)
800 scr_disabled_for_loading = false;
801 Con_Printf ("load failed.\n");
808 if (!scr_initialized || !con_initialized)
809 return; // not initialized yet
812 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
815 // determine size of refresh window
817 if (oldfov != scr_fov.value)
819 oldfov = scr_fov.value;
820 vid.recalc_refdef = true;
823 if (oldscreensize != scr_viewsize.value)
825 oldscreensize = scr_viewsize.value;
826 vid.recalc_refdef = true;
829 if (vid.recalc_refdef)
834 glClearColor(0,0,0,0);
835 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
839 // do 3D refresh drawing, and then update the screen
841 SCR_SetUpToDrawConsole();
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);
884 Draw_String(0, vid.height - sb_lines - 56, r_speeds2_string1, 80);
885 Draw_String(0, vid.height - sb_lines - 48, r_speeds2_string2, 80);
886 Draw_String(0, vid.height - sb_lines - 40, r_speeds2_string3, 80);
887 Draw_String(0, vid.height - sb_lines - 32, r_speeds2_string4, 80);
888 Draw_String(0, vid.height - sb_lines - 24, r_speeds2_string5, 80);
889 Draw_String(0, vid.height - sb_lines - 16, r_speeds2_string6, 80);
890 Draw_String(0, vid.height - sb_lines - 8, r_speeds2_string7, 80);
901 time2 = Sys_DoubleTime ();
902 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);
907 // for profiling, this is separated