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 = {CVAR_SAVE, "viewsize","100"};
80 cvar_t scr_fov = {CVAR_SAVE, "fov","90"}; // 10 - 170
81 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
82 cvar_t scr_centertime = {0, "scr_centertime","2"};
83 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
84 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
85 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
86 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
87 cvar_t showfps = {CVAR_SAVE, "showfps", "0"};
88 cvar_t r_render = {0, "r_render", "1"};
89 cvar_t r_brightness = {CVAR_SAVE, "r_brightness", "1"}; // LordHavoc: a method of operating system independent color correction
90 cvar_t r_contrast = {CVAR_SAVE, "r_contrast", "1"}; // LordHavoc: a method of operating system independent color correction
92 qboolean scr_initialized; // ready to draw
104 qboolean scr_disabled_for_loading;
105 //qboolean scr_drawloading;
106 //float scr_disabled_time;
108 void SCR_ScreenShot_f (void);
111 ===============================================================================
115 ===============================================================================
118 char scr_centerstring[1024];
119 float scr_centertime_start; // for slow victory printing
120 float scr_centertime_off;
121 int scr_center_lines;
123 int scr_erase_center;
129 Called for important messages that should stay in the center of the screen
133 void SCR_CenterPrint (char *str)
135 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
136 scr_centertime_off = scr_centertime.value;
137 scr_centertime_start = cl.time;
139 // count the number of lines for centering
140 scr_center_lines = 1;
150 void SCR_DrawCenterString (void)
157 // the finale prints the characters one at a time
159 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
163 scr_erase_center = 0;
164 start = scr_centerstring;
166 if (scr_center_lines <= 4)
173 // scan the width of the line
174 for (l=0 ; l<40 ; l++)
175 if (start[l] == '\n' || !start[l])
177 x = (vid.width - l*8)/2;
178 // LordHavoc: speedup
183 Draw_String(x, y, start, l);
189 for (j=0 ; j<l ; j++, x+=8)
191 Draw_Character (x, y, start[j]);
199 while (*start && *start != '\n')
204 start++; // skip the \n
208 void SCR_CheckDrawCenterString (void)
210 if (scr_center_lines > scr_erase_lines)
211 scr_erase_lines = scr_center_lines;
213 scr_centertime_off -= host_frametime;
215 if (scr_centertime_off <= 0 && !cl.intermission)
217 if (key_dest != key_game)
220 SCR_DrawCenterString ();
223 //=============================================================================
230 float CalcFov (float fov_x, float width, float height)
235 if (fov_x < 1 || fov_x > 179)
236 Sys_Error ("Bad fov: %f", fov_x);
238 x = width/tan(fov_x/360*M_PI);
251 Must be called whenever vid changes
255 static void SCR_CalcRefdef (void)
259 qboolean full = false;
262 vid.recalc_refdef = 0;
264 //========================================
267 if (scr_viewsize.value < 30)
268 Cvar_Set ("viewsize","30");
269 if (scr_viewsize.value > 120)
270 Cvar_Set ("viewsize","120");
272 // bound field of view
273 if (scr_fov.value < 10)
274 Cvar_Set ("fov","10");
275 if (scr_fov.value > 170)
276 Cvar_Set ("fov","170");
278 // intermission is always full screen
287 if (scr_viewsize.value >= 120)
288 sb_lines = 0; // no status bar at all
289 else if (scr_viewsize.value >= 110)
290 sb_lines = 24; // no inventory
294 if (scr_viewsize.value >= 100.0)
300 size = scr_viewsize.value * (1.0f / 100.0f);
303 // LordHavoc: always fullscreen 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 R_Clip_DisplayBuffer(void);
787 void SCR_UpdateScreen (void)
789 double time1 = 0, time2;
792 time1 = Sys_DoubleTime ();
794 VID_UpdateGamma(false);
796 if (scr_disabled_for_loading)
799 if (realtime - scr_disabled_time > 60)
801 scr_disabled_for_loading = false;
802 Con_Printf ("load failed.\n");
809 if (!scr_initialized || !con_initialized)
810 return; // not initialized yet
813 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
815 if (gl_combine.value && !gl_combine_extension)
816 Cvar_SetValue("gl_combine", false);
818 lighthalf = gl_lightmode.value;
824 if (gl_combine.value)
827 lightscale = 1.0f / (float) (1 << lightscalebit);
830 // determine size of refresh window
832 if (oldfov != scr_fov.value)
834 oldfov = scr_fov.value;
835 vid.recalc_refdef = true;
838 if (oldscreensize != scr_viewsize.value)
840 oldscreensize = scr_viewsize.value;
841 vid.recalc_refdef = true;
844 if (vid.recalc_refdef)
849 glClearColor(0,0,0,0);
850 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
854 // do 3D refresh drawing, and then update the screen
856 SCR_SetUpToDrawConsole();
862 R_Clip_DisplayBuffer();
868 SCR_CheckDrawCenterString();
873 DrawCrosshair(crosshair.value - 1);
875 if (cl.intermission == 1)
876 Sbar_IntermissionOverlay();
877 else if (cl.intermission == 2)
878 Sbar_FinaleOverlay();
885 // if (scr_drawloading)
886 // SCR_DrawLoading();
890 static double currtime;
894 newtime = Sys_DoubleTime();
895 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
896 sprintf(temp, "%4i fps", calc);
898 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
901 // LordHavoc: only print info if renderer is being used
902 if (r_speeds2.value && !con_forcedup)
906 for (i = 0;r_speeds2_string[i];i++)
907 if (r_speeds2_string[i] == '\n')
909 y = vid.height - sb_lines - lines * 8 - 8;
911 while (r_speeds2_string[i])
914 while (r_speeds2_string[i] && r_speeds2_string[i] != '\n')
917 Draw_String(0, y, r_speeds2_string + j, i - j);
918 if (r_speeds2_string[i] == '\n')
932 time2 = Sys_DoubleTime ();
933 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);
938 // for profiling, this is separated