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};
92 cvar_t r_render = {"r_render", "1"};
94 extern cvar_t crosshair;
96 qboolean scr_initialized; // ready to draw
109 extern viddef_t vid; // global video state
111 qboolean scr_disabled_for_loading;
112 qboolean scr_drawloading;
113 float scr_disabled_time;
115 void SCR_ScreenShot_f (void);
118 ===============================================================================
122 ===============================================================================
125 char scr_centerstring[1024];
126 float scr_centertime_start; // for slow victory printing
127 float scr_centertime_off;
128 int scr_center_lines;
130 int scr_erase_center;
136 Called for important messages that should stay in the center of the screen
140 void SCR_CenterPrint (char *str)
142 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
143 scr_centertime_off = scr_centertime.value;
144 scr_centertime_start = cl.time;
146 // count the number of lines for centering
147 scr_center_lines = 1;
157 void SCR_DrawCenterString (void)
164 // the finale prints the characters one at a time
166 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
170 scr_erase_center = 0;
171 start = scr_centerstring;
173 if (scr_center_lines <= 4)
180 // scan the width of the line
181 for (l=0 ; l<40 ; l++)
182 if (start[l] == '\n' || !start[l])
184 x = (vid.width - l*8)/2;
185 // LordHavoc: speedup
190 Draw_String(x, y, start, l);
196 for (j=0 ; j<l ; j++, x+=8)
198 Draw_Character (x, y, start[j]);
206 while (*start && *start != '\n')
211 start++; // skip the \n
215 void SCR_CheckDrawCenterString (void)
218 if (scr_center_lines > scr_erase_lines)
219 scr_erase_lines = scr_center_lines;
221 scr_centertime_off -= host_frametime;
223 if (scr_centertime_off <= 0 && !cl.intermission)
225 if (key_dest != key_game)
228 SCR_DrawCenterString ();
231 //=============================================================================
238 float CalcFov (float fov_x, float width, float height)
243 if (fov_x < 1 || fov_x > 179)
244 Sys_Error ("Bad fov: %f", fov_x);
246 x = width/tan(fov_x/360*M_PI);
259 Must be called whenever vid changes
263 static void SCR_CalcRefdef (void)
267 qboolean full = false;
270 scr_fullupdate = 0; // force a background redraw
271 vid.recalc_refdef = 0;
273 //========================================
276 if (scr_viewsize.value < 30)
277 Cvar_Set ("viewsize","30");
278 if (scr_viewsize.value > 120)
279 Cvar_Set ("viewsize","120");
281 // bound field of view
282 if (scr_fov.value < 10)
283 Cvar_Set ("fov","10");
284 if (scr_fov.value > 170)
285 Cvar_Set ("fov","170");
287 // intermission is always full screen
291 size = scr_viewsize.value;
294 sb_lines = 0; // no status bar at all
295 else if (size >= 110)
296 sb_lines = 24; // no inventory
300 if (scr_viewsize.value >= 100.0)
306 size = scr_viewsize.value;
315 // LordHavoc: always fullyscreen rendering
316 h = vid.height/* - sb_lines*/;
318 r_refdef.vrect.width = vid.width * size;
319 if (r_refdef.vrect.width < 96)
321 size = 96.0 / r_refdef.vrect.width;
322 r_refdef.vrect.width = 96; // min for icons
325 r_refdef.vrect.height = vid.height * size;
326 //if (r_refdef.vrect.height > vid.height - sb_lines)
327 // r_refdef.vrect.height = vid.height - sb_lines;
328 if (r_refdef.vrect.height > (int) vid.height)
329 r_refdef.vrect.height = vid.height;
330 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
332 r_refdef.vrect.y = 0;
334 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
336 r_refdef.fov_x = scr_fov.value;
337 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
348 void SCR_SizeUp_f (void)
350 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
351 vid.recalc_refdef = 1;
362 void SCR_SizeDown_f (void)
364 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
365 vid.recalc_refdef = 1;
368 //============================================================================
370 void gl_screen_start()
372 scr_ram = Draw_PicFromWad ("ram");
373 scr_net = Draw_PicFromWad ("net");
374 scr_turtle = Draw_PicFromWad ("turtle");
377 void gl_screen_shutdown()
386 void GL_Screen_Init (void)
389 Cvar_RegisterVariable (&scr_fov);
390 Cvar_RegisterVariable (&scr_viewsize);
391 Cvar_RegisterVariable (&scr_conspeed);
392 Cvar_RegisterVariable (&scr_showram);
393 Cvar_RegisterVariable (&scr_showturtle);
394 Cvar_RegisterVariable (&scr_showpause);
395 Cvar_RegisterVariable (&scr_centertime);
396 Cvar_RegisterVariable (&scr_printspeed);
397 Cvar_RegisterVariable (&showfps);
398 Cvar_RegisterVariable (&r_render);
404 // register our commands
406 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
407 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
408 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
410 scr_initialized = true;
412 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown);
422 void SCR_DrawRam (void)
424 if (!scr_showram.value)
430 Draw_Pic (32, 0, scr_ram);
438 void SCR_DrawTurtle (void)
442 if (!scr_showturtle.value)
445 if (host_frametime < 0.1)
455 Draw_Pic (0, 0, scr_turtle);
463 void SCR_DrawNet (void)
465 if (realtime - cl.last_received_message < 0.3)
467 if (cls.demoplayback)
470 Draw_Pic (64, 0, scr_net);
478 void SCR_DrawPause (void)
482 if (!scr_showpause.value) // turn off for screenshots
488 pic = Draw_CachePic ("gfx/pause.lmp");
489 Draw_Pic ( (vid.width - pic->width)/2,
490 (vid.height - 48 - pic->height)/2, pic);
500 void SCR_DrawLoading (void)
504 if (!scr_drawloading)
507 pic = Draw_CachePic ("gfx/loading.lmp");
508 Draw_Pic ( (vid.width - pic->width)/2,
509 (vid.height - 48 - pic->height)/2, pic);
514 //=============================================================================
519 SCR_SetUpToDrawConsole
522 void SCR_SetUpToDrawConsole (void)
526 //if (scr_drawloading)
527 // return; // never a console with loading plaque
529 // decide on the height of the console
530 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
534 scr_conlines = vid.height; // full screen
535 scr_con_current = scr_conlines;
537 else if (key_dest == key_console)
538 scr_conlines = vid.height/2; // half screen
540 scr_conlines = 0; // none visible
542 if (scr_conlines < scr_con_current)
544 scr_con_current -= scr_conspeed.value*host_frametime;
545 if (scr_conlines > scr_con_current)
546 scr_con_current = scr_conlines;
549 else if (scr_conlines > scr_con_current)
551 scr_con_current += scr_conspeed.value*host_frametime;
552 if (scr_conlines < scr_con_current)
553 scr_con_current = scr_conlines;
562 void SCR_DrawConsole (void)
566 scr_copyeverything = 1;
567 Con_DrawConsole (scr_con_current, true);
572 if (key_dest == key_game || key_dest == key_message)
573 Con_DrawNotify (); // only draw notify in game
579 ==============================================================================
583 ==============================================================================
591 void SCR_ScreenShot_f (void)
595 char checkname[MAX_OSPATH];
598 // find a file name to save it to
600 strcpy(filename,"dp0000.tga");
602 for (i=0 ; i<=9999 ; i++)
604 filename[2] = (i/1000)%10 + '0';
605 filename[3] = (i/ 100)%10 + '0';
606 filename[4] = (i/ 10)%10 + '0';
607 filename[5] = (i/ 1)%10 + '0';
608 sprintf (checkname, "%s/%s", com_gamedir, filename);
609 if (Sys_FileTime(checkname) == -1)
610 break; // file doesn't exist
614 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
618 buffer = malloc(glwidth*glheight*3);
619 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
620 Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
623 Con_Printf ("Wrote %s\n", filename);
627 //=============================================================================
632 SCR_BeginLoadingPlaque
636 void SCR_BeginLoadingPlaque (void)
638 S_StopAllSounds (true);
640 if (cls.state != ca_connected)
642 if (cls.signon != SIGNONS)
645 // redraw with no console and the loading plaque
647 scr_centertime_off = 0;
650 scr_drawloading = true;
653 scr_drawloading = false;
655 scr_disabled_for_loading = true;
656 scr_disabled_time = realtime;
666 void SCR_EndLoadingPlaque (void)
668 scr_disabled_for_loading = false;
673 //=============================================================================
675 char *scr_notifystring;
676 qboolean scr_drawdialog;
678 void SCR_DrawNotifyString (void)
684 start = scr_notifystring;
690 // scan the width of the line
691 for (l=0 ; l<40 ; l++)
692 if (start[l] == '\n' || !start[l])
694 x = (vid.width - l*8)/2;
695 // LordHavoc: speedup
696 // for (j=0 ; j<l ; j++, x+=8)
697 // Draw_Character (x, y, start[j]);
698 Draw_String (x, y, start, l);
702 while (*start && *start != '\n')
707 start++; // skip the \n
715 Displays a text string in the center of the screen and waits for a Y or N
719 int SCR_ModalMessage (char *text)
721 if (cls.state == ca_dedicated)
724 scr_notifystring = text;
726 // draw a fresh screen
728 scr_drawdialog = true;
730 scr_drawdialog = false;
732 S_ClearBuffer (); // so dma doesn't loop current sound
736 key_count = -1; // wait for a key down and up
737 Sys_SendKeyEvents ();
738 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
743 return key_lastpress == 'y';
747 //=============================================================================
753 Brings the console down and fades the blends back to normal
756 void SCR_BringDownConsole (void)
760 scr_centertime_off = 0;
762 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
765 cl.cshifts[0].percent = 0; // no area contents blend on next frame
768 void DrawCrosshair(int num);
769 void GL_Set2D (void);
771 extern void SHOWLMP_drawall();
772 extern cvar_t contrast;
773 extern cvar_t brightness;
774 extern cvar_t gl_lightmode;
776 void GL_BrightenScreen()
781 glDisable(GL_TEXTURE_2D);
783 f = brightness.value = bound(1.0f, brightness.value, 5.0f);
786 glBlendFunc (GL_DST_COLOR, GL_ONE);
787 glBegin (GL_TRIANGLES);
793 glColor3f (f-1, f-1, f-1);
794 glVertex2f (-5000, -5000);
795 glVertex2f (10000, -5000);
796 glVertex2f (-5000, 10000);
801 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
802 contrast.value = bound(0.2, contrast.value, 1.0);
803 if (contrast.value < 0.99f)
805 glBegin (GL_TRIANGLES);
806 glColor4f (1, 1, 1, 1-contrast.value);
807 glVertex2f (-5000, -5000);
808 glVertex2f (10000, -5000);
809 glVertex2f (-5000, 10000);
813 glEnable (GL_CULL_FACE);
814 glEnable (GL_DEPTH_TEST);
816 glEnable(GL_TEXTURE_2D);
823 This is called every frame, and can also be called explicitly to flush
826 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
829 extern cvar_t gl_vertexarrays;
830 extern qboolean gl_arrays;
832 void SCR_UpdateScreen (void)
834 double time1 = 0, time2;
837 time1 = Sys_FloatTime ();
840 gl_vertexarrays.value = 0;
843 scr_copyeverything = 0;
845 if (scr_disabled_for_loading)
847 if (realtime - scr_disabled_time > 60)
849 scr_disabled_for_loading = false;
850 Con_Printf ("load failed.\n");
856 if (!scr_initialized || !con_initialized)
857 return; // not initialized yet
860 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
863 // determine size of refresh window
865 if (oldfov != scr_fov.value)
867 oldfov = scr_fov.value;
868 vid.recalc_refdef = true;
871 if (oldscreensize != scr_viewsize.value)
873 oldscreensize = scr_viewsize.value;
874 vid.recalc_refdef = true;
877 if (vid.recalc_refdef)
882 glClearColor(0,0,0,0);
883 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
887 // do 3D refresh drawing, and then update the screen
889 SCR_SetUpToDrawConsole ();
898 // Draw_FadeScreen ();
899 SCR_DrawNotifyString ();
900 scr_copyeverything = true;
902 else if (scr_drawloading)
907 else if (cl.intermission == 1 && key_dest == key_game)
909 Sbar_IntermissionOverlay ();
911 else if (cl.intermission == 2 && key_dest == key_game)
913 Sbar_FinaleOverlay ();
914 SCR_CheckDrawCenterString ();
919 DrawCrosshair(crosshair.value - 1);
925 SCR_CheckDrawCenterString ();
934 static double currtime;
938 newtime = Sys_FloatTime();
939 calc = (int) (100.0 / (newtime - currtime));
940 sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
942 Draw_String(vid.width - (12*8), 0, temp, 9999);
953 time2 = Sys_FloatTime ();
954 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);
959 // for profiling, this is seperated