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 float scr_con_current;
74 float scr_conlines; // lines of console to display
76 float oldscreensize, oldfov;
77 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
78 cvar_t scr_fov = {CVAR_SAVE, "fov","90"}; // 10 - 170
79 cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
80 cvar_t scr_centertime = {0, "scr_centertime","2"};
81 cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
82 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
83 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
84 cvar_t scr_printspeed = {0, "scr_printspeed","8"};
85 cvar_t showfps = {CVAR_SAVE, "showfps", "0"};
86 cvar_t r_render = {0, "r_render", "1"};
87 cvar_t r_brightness = {CVAR_SAVE, "r_brightness", "1"}; // LordHavoc: a method of operating system independent color correction
88 cvar_t r_contrast = {CVAR_SAVE, "r_contrast", "1"}; // LordHavoc: a method of operating system independent color correction
90 qboolean scr_initialized; // ready to draw
102 qboolean scr_disabled_for_loading;
103 //qboolean scr_drawloading;
104 //float scr_disabled_time;
106 void SCR_ScreenShot_f (void);
109 ===============================================================================
113 ===============================================================================
116 char scr_centerstring[1024];
117 float scr_centertime_start; // for slow victory printing
118 float scr_centertime_off;
119 int scr_center_lines;
121 int scr_erase_center;
127 Called for important messages that should stay in the center of the screen
131 void SCR_CenterPrint (char *str)
133 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
134 scr_centertime_off = scr_centertime.value;
135 scr_centertime_start = cl.time;
137 // count the number of lines for centering
138 scr_center_lines = 1;
148 void SCR_DrawCenterString (void)
155 // the finale prints the characters one at a time
157 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
161 scr_erase_center = 0;
162 start = scr_centerstring;
164 if (scr_center_lines <= 4)
165 y = vid.conheight*0.35;
171 // scan the width of the line
172 for (l=0 ; l<40 ; l++)
173 if (start[l] == '\n' || !start[l])
175 x = (vid.conwidth - l*8)/2;
176 // LordHavoc: speedup
181 Draw_String(x, y, start, l);
187 for (j=0 ; j<l ; j++, x+=8)
189 Draw_Character (x, y, start[j]);
197 while (*start && *start != '\n')
202 start++; // skip the \n
206 void SCR_CheckDrawCenterString (void)
208 if (scr_center_lines > scr_erase_lines)
209 scr_erase_lines = scr_center_lines;
211 scr_centertime_off -= host_frametime;
213 if (scr_centertime_off <= 0 && !cl.intermission)
215 if (key_dest != key_game)
218 SCR_DrawCenterString ();
221 //=============================================================================
228 float CalcFov (float fov_x, float width, float height)
230 // calculate vision size and alter by aspect, then convert back to angle
231 return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
238 Must be called whenever vid changes
242 static void SCR_CalcRefdef (void)
246 // vid.recalc_refdef = 0;
248 //========================================
251 if (scr_viewsize.value < 30)
252 Cvar_Set ("viewsize","30");
253 if (scr_viewsize.value > 120)
254 Cvar_Set ("viewsize","120");
256 // bound field of view
257 if (scr_fov.value < 10)
258 Cvar_Set ("fov","10");
259 if (scr_fov.value > 170)
260 Cvar_Set ("fov","170");
262 // intermission is always full screen
270 if (scr_viewsize.value >= 120)
271 sb_lines = 0; // no status bar at all
272 else if (scr_viewsize.value >= 110)
273 sb_lines = 24; // no inventory
276 size = scr_viewsize.value * (1.0 / 100.0);
281 r_refdef.width = vid.realwidth;
282 r_refdef.height = vid.realheight;
288 r_refdef.width = vid.realwidth * size;
289 r_refdef.height = vid.realheight * size;
290 r_refdef.x = (vid.realwidth - r_refdef.width)/2;
291 r_refdef.y = (vid.realheight - r_refdef.height)/2;
294 r_refdef.fov_x = scr_fov.value;
295 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
297 r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
298 r_refdef.height = bound(0, r_refdef.height, vid.realheight);
299 r_refdef.x = bound(0, r_refdef.x, vid.realwidth) + vid.realx;
300 r_refdef.y = bound(0, r_refdef.y, vid.realheight) + vid.realy;
311 void SCR_SizeUp_f (void)
313 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
314 // vid.recalc_refdef = 1;
325 void SCR_SizeDown_f (void)
327 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
328 // vid.recalc_refdef = 1;
331 //============================================================================
333 void gl_screen_start(void)
335 scr_ram = Draw_PicFromWad ("ram");
336 scr_net = Draw_PicFromWad ("net");
337 scr_turtle = Draw_PicFromWad ("turtle");
340 void gl_screen_shutdown(void)
344 void gl_screen_newmap(void)
353 void GL_Screen_Init (void)
356 Cvar_RegisterVariable (&scr_fov);
357 Cvar_RegisterVariable (&scr_viewsize);
358 Cvar_RegisterVariable (&scr_conspeed);
359 Cvar_RegisterVariable (&scr_showram);
360 Cvar_RegisterVariable (&scr_showturtle);
361 Cvar_RegisterVariable (&scr_showpause);
362 Cvar_RegisterVariable (&scr_centertime);
363 Cvar_RegisterVariable (&scr_printspeed);
364 Cvar_RegisterVariable (&showfps);
365 Cvar_RegisterVariable (&r_render);
366 Cvar_RegisterVariable (&r_brightness);
367 Cvar_RegisterVariable (&r_contrast);
373 // register our commands
375 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
376 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
377 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
379 scr_initialized = true;
381 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
391 void SCR_DrawRam (void)
393 // if (!scr_showram.value)
395 // Draw_Pic (32, 0, scr_ram);
403 void SCR_DrawTurtle (void)
407 if (!scr_showturtle.value)
410 if (cl.frametime < 0.1)
420 Draw_Pic (0, 0, scr_turtle);
428 void SCR_DrawNet (void)
430 if (realtime - cl.last_received_message < 0.3)
432 if (cls.demoplayback)
435 Draw_Pic (64, 0, scr_net);
443 void SCR_DrawPause (void)
447 if (!scr_showpause.value) // turn off for screenshots
453 pic = Draw_CachePic ("gfx/pause.lmp");
454 Draw_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, pic);
465 void SCR_DrawLoading (void)
469 if (!scr_drawloading)
472 pic = Draw_CachePic ("gfx/loading.lmp");
473 Draw_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, pic);
479 //=============================================================================
484 SCR_SetUpToDrawConsole
487 void SCR_SetUpToDrawConsole (void)
491 //if (scr_drawloading)
492 // return; // never a console with loading plaque
494 // decide on the height of the console
495 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
499 scr_conlines = vid.conheight; // full screen
500 scr_con_current = scr_conlines;
502 else if (key_dest == key_console)
503 scr_conlines = vid.conheight/2; // half screen
505 scr_conlines = 0; // none visible
507 if (scr_conlines < scr_con_current)
509 scr_con_current -= scr_conspeed.value*host_realframetime;
510 if (scr_conlines > scr_con_current)
511 scr_con_current = scr_conlines;
514 else if (scr_conlines > scr_con_current)
516 scr_con_current += scr_conspeed.value*host_realframetime;
517 if (scr_conlines < scr_con_current)
518 scr_con_current = scr_conlines;
527 void SCR_DrawConsole (void)
531 Con_DrawConsole (scr_con_current, true);
536 if (key_dest == key_game || key_dest == key_message)
537 Con_DrawNotify (); // only draw notify in game
543 ==============================================================================
547 ==============================================================================
555 void SCR_ScreenShot_f (void)
557 byte *buffer, gamma[256];
559 char checkname[MAX_OSPATH];
562 // find a file name to save it to
564 strcpy(filename,"dp0000.tga");
566 for (i=0 ; i<=9999 ; i++)
568 filename[2] = (i/1000)%10 + '0';
569 filename[3] = (i/ 100)%10 + '0';
570 filename[4] = (i/ 10)%10 + '0';
571 filename[5] = (i/ 1)%10 + '0';
572 sprintf (checkname, "%s/%s", com_gamedir, filename);
573 if (Sys_FileTime(checkname) == -1)
574 break; // file doesn't exist
578 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
582 buffer = qmalloc(vid.realwidth*vid.realheight*3);
583 glReadPixels (vid.realx, vid.realy, vid.realwidth, vid.realheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
585 // apply hardware gamma to the image
586 BuildGammaTable8((lighthalf && hardwaregammasupported) ? 2.0f : 1.0f, 1, 1, 0, gamma);
587 Image_GammaRemapRGB(buffer, buffer, vid.realwidth*vid.realheight, gamma, gamma, gamma);
589 Image_WriteTGARGB_preflipped(filename, vid.realwidth, vid.realheight, buffer);
592 Con_Printf ("Wrote %s\n", filename);
596 //=============================================================================
601 SCR_BeginLoadingPlaque
606 void SCR_BeginLoadingPlaque (void)
608 S_StopAllSounds (true);
610 // if (cls.state != ca_connected)
612 // if (cls.signon != SIGNONS)
615 // redraw with no console and the loading plaque
616 // Con_ClearNotify ();
617 // scr_centertime_off = 0;
618 // scr_con_current = 0;
620 scr_drawloading = true;
623 // scr_disabled_for_loading = true;
624 // scr_disabled_time = realtime;
635 void SCR_EndLoadingPlaque (void)
637 // scr_disabled_for_loading = false;
638 scr_drawloading = false;
643 //=============================================================================
645 char *scr_notifystring;
647 void SCR_DrawNotifyString (void)
653 start = scr_notifystring;
655 y = vid.conheight*0.35;
659 // scan the width of the line
660 for (l=0 ; l<40 ; l++)
661 if (start[l] == '\n' || !start[l])
663 x = (vid.conwidth - l*8)/2;
664 // LordHavoc: speedup
665 // for (j=0 ; j<l ; j++, x+=8)
666 // Draw_Character (x, y, start[j]);
667 Draw_String (x, y, start, l);
671 while (*start && *start != '\n')
676 start++; // skip the \n
680 //=============================================================================
682 void DrawCrosshair(int num);
683 void GL_Set2D (void);
685 void GL_BrightenScreen(void)
689 if (r_brightness.value < 0.1f)
690 Cvar_SetValue("r_brightness", 0.1f);
691 if (r_brightness.value > 5.0f)
692 Cvar_SetValue("r_brightness", 5.0f);
694 if (r_contrast.value < 0.2f)
695 Cvar_SetValue("r_contrast", 0.2f);
696 if (r_contrast.value > 1.0f)
697 Cvar_SetValue("r_contrast", 1.0f);
699 if (!(lighthalf && !hardwaregammasupported) && r_brightness.value < 1.01f && r_contrast.value > 0.99f)
705 glDisable(GL_TEXTURE_2D);
707 f = r_brightness.value;
708 // only apply lighthalf using software color correction if hardware is not available (speed reasons)
709 if (lighthalf && !hardwaregammasupported)
713 glBlendFunc (GL_DST_COLOR, GL_ONE);
714 glBegin (GL_TRIANGLES);
720 glColor3f (f-1, f-1, f-1);
721 glVertex2f (-5000, -5000);
722 glVertex2f (10000, -5000);
723 glVertex2f (-5000, 10000);
728 if (r_contrast.value <= 0.99f)
730 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
731 if (lighthalf && hardwaregammasupported)
732 glColor4f (0.5, 0.5, 0.5, 1 - r_contrast.value);
734 glColor4f (1, 1, 1, 1 - r_contrast.value);
735 glBegin (GL_TRIANGLES);
736 glVertex2f (-5000, -5000);
737 glVertex2f (10000, -5000);
738 glVertex2f (-5000, 10000);
741 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
743 glEnable (GL_CULL_FACE);
744 glEnable (GL_DEPTH_TEST);
746 glEnable(GL_TEXTURE_2D);
753 This is called every frame, and can also be called explicitly to flush
756 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
759 void GL_Finish(void);
760 void R_Clip_DisplayBuffer(void);
761 void SCR_UpdateScreen (void)
763 double time1 = 0, time2;
766 time1 = Sys_DoubleTime ();
768 VID_UpdateGamma(false);
770 if (scr_disabled_for_loading)
773 if (realtime - scr_disabled_time > 60)
775 scr_disabled_for_loading = false;
776 Con_Printf ("load failed.\n");
783 if (!scr_initialized || !con_initialized)
784 return; // not initialized yet
787 GL_BeginRendering (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
789 if (gl_combine.value && !gl_combine_extension)
790 Cvar_SetValue("gl_combine", false);
792 lighthalf = gl_lightmode.value;
798 if (gl_combine.value)
801 lightscale = 1.0f / (float) (1 << lightscalebit);
804 // determine size of refresh window
806 if (oldfov != scr_fov.value)
808 oldfov = scr_fov.value;
809 // vid.recalc_refdef = true;
812 if (oldscreensize != scr_viewsize.value)
814 oldscreensize = scr_viewsize.value;
815 // vid.recalc_refdef = true;
818 // if (vid.recalc_refdef)
823 glClearColor(0,0,0,0);
824 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
828 // do 3D refresh drawing, and then update the screen
830 SCR_SetUpToDrawConsole();
836 R_Clip_DisplayBuffer();
842 SCR_CheckDrawCenterString();
847 DrawCrosshair(crosshair.value - 1);
849 if (cl.intermission == 1)
850 Sbar_IntermissionOverlay();
851 else if (cl.intermission == 2)
852 Sbar_FinaleOverlay();
859 // if (scr_drawloading)
860 // SCR_DrawLoading();
864 static double currtime;
868 newtime = Sys_DoubleTime();
869 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
870 sprintf(temp, "%4i fps", calc);
872 Draw_String(vid.conwidth - (8*8), vid.conheight - sb_lines - 8, temp, 9999);
875 if (r_speeds2.value && r_speeds2_string[0])
879 for (i = 0;r_speeds2_string[i];i++)
880 if (r_speeds2_string[i] == '\n')
882 y = vid.conheight - sb_lines - lines * 8 - 8;
884 while (r_speeds2_string[i])
887 while (r_speeds2_string[i] && r_speeds2_string[i] != '\n')
890 Draw_String(0, y, r_speeds2_string + j, i - j);
891 if (r_speeds2_string[i] == '\n')
895 // clear so it won't reprint without renderer being called again
896 r_speeds2_string[0] = 0;
907 time2 = Sys_DoubleTime ();
908 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);
913 // for profiling, this is separated