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 // 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()
381 void gl_screen_newmap()
390 void GL_Screen_Init (void)
393 Cvar_RegisterVariable (&scr_fov);
394 Cvar_RegisterVariable (&scr_viewsize);
395 Cvar_RegisterVariable (&scr_conspeed);
396 Cvar_RegisterVariable (&scr_showram);
397 Cvar_RegisterVariable (&scr_showturtle);
398 Cvar_RegisterVariable (&scr_showpause);
399 Cvar_RegisterVariable (&scr_centertime);
400 Cvar_RegisterVariable (&scr_printspeed);
401 Cvar_RegisterVariable (&showfps);
402 Cvar_RegisterVariable (&r_render);
408 // register our commands
410 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
411 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
412 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
414 scr_initialized = true;
416 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
426 void SCR_DrawRam (void)
428 if (!scr_showram.value)
434 Draw_Pic (32, 0, scr_ram);
442 void SCR_DrawTurtle (void)
446 if (!scr_showturtle.value)
449 if (cl.frametime < 0.1)
459 Draw_Pic (0, 0, scr_turtle);
467 void SCR_DrawNet (void)
469 if (realtime - cl.last_received_message < 0.3)
471 if (cls.demoplayback)
474 Draw_Pic (64, 0, scr_net);
482 void SCR_DrawPause (void)
486 if (!scr_showpause.value) // turn off for screenshots
492 pic = Draw_CachePic ("gfx/pause.lmp");
493 Draw_Pic ( (vid.width - pic->width)/2,
494 (vid.height - 48 - pic->height)/2, pic);
504 void SCR_DrawLoading (void)
508 if (!scr_drawloading)
511 pic = Draw_CachePic ("gfx/loading.lmp");
512 Draw_Pic ( (vid.width - pic->width)/2,
513 (vid.height - 48 - pic->height)/2, pic);
518 //=============================================================================
523 SCR_SetUpToDrawConsole
526 void SCR_SetUpToDrawConsole (void)
530 //if (scr_drawloading)
531 // return; // never a console with loading plaque
533 // decide on the height of the console
534 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
538 scr_conlines = vid.height; // full screen
539 scr_con_current = scr_conlines;
541 else if (key_dest == key_console)
542 scr_conlines = vid.height/2; // half screen
544 scr_conlines = 0; // none visible
546 if (scr_conlines < scr_con_current)
548 scr_con_current -= scr_conspeed.value*host_realframetime;
549 if (scr_conlines > scr_con_current)
550 scr_con_current = scr_conlines;
553 else if (scr_conlines > scr_con_current)
555 scr_con_current += scr_conspeed.value*host_realframetime;
556 if (scr_conlines < scr_con_current)
557 scr_con_current = scr_conlines;
566 void SCR_DrawConsole (void)
570 scr_copyeverything = 1;
571 Con_DrawConsole (scr_con_current, true);
576 if (key_dest == key_game || key_dest == key_message)
577 Con_DrawNotify (); // only draw notify in game
583 ==============================================================================
587 ==============================================================================
595 void SCR_ScreenShot_f (void)
599 char checkname[MAX_OSPATH];
602 // find a file name to save it to
604 strcpy(filename,"dp0000.tga");
606 for (i=0 ; i<=9999 ; i++)
608 filename[2] = (i/1000)%10 + '0';
609 filename[3] = (i/ 100)%10 + '0';
610 filename[4] = (i/ 10)%10 + '0';
611 filename[5] = (i/ 1)%10 + '0';
612 sprintf (checkname, "%s/%s", com_gamedir, filename);
613 if (Sys_FileTime(checkname) == -1)
614 break; // file doesn't exist
618 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
622 buffer = qmalloc(glwidth*glheight*3);
623 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
624 Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
627 Con_Printf ("Wrote %s\n", filename);
631 //=============================================================================
636 SCR_BeginLoadingPlaque
640 void SCR_BeginLoadingPlaque (void)
642 S_StopAllSounds (true);
644 if (cls.state != ca_connected)
646 if (cls.signon != SIGNONS)
649 // redraw with no console and the loading plaque
651 scr_centertime_off = 0;
654 scr_drawloading = true;
657 scr_drawloading = false;
659 scr_disabled_for_loading = true;
660 scr_disabled_time = realtime;
670 void SCR_EndLoadingPlaque (void)
672 scr_disabled_for_loading = false;
677 //=============================================================================
679 char *scr_notifystring;
680 qboolean scr_drawdialog;
682 void SCR_DrawNotifyString (void)
688 start = scr_notifystring;
694 // scan the width of the line
695 for (l=0 ; l<40 ; l++)
696 if (start[l] == '\n' || !start[l])
698 x = (vid.width - l*8)/2;
699 // LordHavoc: speedup
700 // for (j=0 ; j<l ; j++, x+=8)
701 // Draw_Character (x, y, start[j]);
702 Draw_String (x, y, start, l);
706 while (*start && *start != '\n')
711 start++; // skip the \n
719 Displays a text string in the center of the screen and waits for a Y or N
723 int SCR_ModalMessage (char *text)
725 if (cls.state == ca_dedicated)
728 scr_notifystring = text;
730 // draw a fresh screen
732 scr_drawdialog = true;
734 scr_drawdialog = false;
736 S_ClearBuffer (); // so dma doesn't loop current sound
740 key_count = -1; // wait for a key down and up
741 Sys_SendKeyEvents ();
742 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
747 return key_lastpress == 'y';
751 //=============================================================================
757 Brings the console down and fades the blends back to normal
760 void SCR_BringDownConsole (void)
764 scr_centertime_off = 0;
766 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
769 cl.cshifts[0].percent = 0; // no area contents blend on next frame
772 void DrawCrosshair(int num);
773 void GL_Set2D (void);
775 extern void SHOWLMP_drawall();
776 extern cvar_t contrast;
777 extern cvar_t brightness;
778 extern cvar_t gl_lightmode;
779 extern cvar_t r_speeds2;
781 void GL_BrightenScreen()
786 glDisable(GL_TEXTURE_2D);
788 f = brightness.value = bound(1.0f, brightness.value, 5.0f);
791 glBlendFunc (GL_DST_COLOR, GL_ONE);
792 glBegin (GL_TRIANGLES);
798 glColor3f (f-1, f-1, f-1);
799 glVertex2f (-5000, -5000);
800 glVertex2f (10000, -5000);
801 glVertex2f (-5000, 10000);
806 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
807 contrast.value = bound(0.2, contrast.value, 1.0);
808 if (contrast.value < 0.99f)
810 glBegin (GL_TRIANGLES);
811 glColor4f (1, 1, 1, 1-contrast.value);
812 glVertex2f (-5000, -5000);
813 glVertex2f (10000, -5000);
814 glVertex2f (-5000, 10000);
818 glEnable (GL_CULL_FACE);
819 glEnable (GL_DEPTH_TEST);
821 glEnable(GL_TEXTURE_2D);
828 This is called every frame, and can also be called explicitly to flush
831 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
835 void SCR_UpdateScreen (void)
837 double time1 = 0, time2;
840 time1 = Sys_FloatTime ();
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) ((1.0 / (newtime - currtime)) + 0.5);
940 sprintf(temp, "%4i fps", calc);
942 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
947 extern char r_speeds2_string1[81], r_speeds2_string2[81], r_speeds2_string3[81], r_speeds2_string4[81], r_speeds2_string5[81], r_speeds2_string6[81], r_speeds2_string7[81];
948 Draw_String(0, vid.height - sb_lines - 56, r_speeds2_string1, 80);
949 Draw_String(0, vid.height - sb_lines - 48, r_speeds2_string2, 80);
950 Draw_String(0, vid.height - sb_lines - 40, r_speeds2_string3, 80);
951 Draw_String(0, vid.height - sb_lines - 32, r_speeds2_string4, 80);
952 Draw_String(0, vid.height - sb_lines - 24, r_speeds2_string5, 80);
953 Draw_String(0, vid.height - sb_lines - 16, r_speeds2_string6, 80);
954 Draw_String(0, vid.height - sb_lines - 8, r_speeds2_string7, 80);
965 time2 = Sys_FloatTime ();
966 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);
971 // for profiling, this is separated