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"};
90 extern cvar_t crosshair;
92 qboolean scr_initialized; // ready to draw
103 extern viddef_t vid; // global video state
105 qboolean scr_disabled_for_loading;
106 //qboolean scr_drawloading;
107 //float scr_disabled_time;
109 void SCR_ScreenShot_f (void);
112 ===============================================================================
116 ===============================================================================
119 char scr_centerstring[1024];
120 float scr_centertime_start; // for slow victory printing
121 float scr_centertime_off;
122 int scr_center_lines;
124 int scr_erase_center;
130 Called for important messages that should stay in the center of the screen
134 void SCR_CenterPrint (char *str)
136 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
137 scr_centertime_off = scr_centertime.value;
138 scr_centertime_start = cl.time;
140 // count the number of lines for centering
141 scr_center_lines = 1;
151 void SCR_DrawCenterString (void)
158 // the finale prints the characters one at a time
160 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
164 scr_erase_center = 0;
165 start = scr_centerstring;
167 if (scr_center_lines <= 4)
174 // scan the width of the line
175 for (l=0 ; l<40 ; l++)
176 if (start[l] == '\n' || !start[l])
178 x = (vid.width - l*8)/2;
179 // LordHavoc: speedup
184 Draw_String(x, y, start, l);
190 for (j=0 ; j<l ; j++, x+=8)
192 Draw_Character (x, y, start[j]);
200 while (*start && *start != '\n')
205 start++; // skip the \n
209 void SCR_CheckDrawCenterString (void)
211 if (scr_center_lines > scr_erase_lines)
212 scr_erase_lines = scr_center_lines;
214 scr_centertime_off -= host_frametime;
216 if (scr_centertime_off <= 0 && !cl.intermission)
218 if (key_dest != key_game)
221 SCR_DrawCenterString ();
224 //=============================================================================
231 float CalcFov (float fov_x, float width, float height)
236 if (fov_x < 1 || fov_x > 179)
237 Sys_Error ("Bad fov: %f", fov_x);
239 x = width/tan(fov_x/360*M_PI);
252 Must be called whenever vid changes
256 static void SCR_CalcRefdef (void)
260 qboolean full = false;
263 vid.recalc_refdef = 0;
265 //========================================
268 if (scr_viewsize.value < 30)
269 Cvar_Set ("viewsize","30");
270 if (scr_viewsize.value > 120)
271 Cvar_Set ("viewsize","120");
273 // bound field of view
274 if (scr_fov.value < 10)
275 Cvar_Set ("fov","10");
276 if (scr_fov.value > 170)
277 Cvar_Set ("fov","170");
279 // intermission is always full screen
283 size = scr_viewsize.value;
286 sb_lines = 0; // no status bar at all
287 else if (size >= 110)
288 sb_lines = 24; // no inventory
292 if (scr_viewsize.value >= 100.0)
298 size = scr_viewsize.value;
307 // LordHavoc: always fullyscreen rendering
308 h = vid.height/* - sb_lines*/;
310 r_refdef.vrect.width = vid.width * size;
311 if (r_refdef.vrect.width < 96)
313 size = 96.0 / r_refdef.vrect.width;
314 r_refdef.vrect.width = 96; // min for icons
317 r_refdef.vrect.height = vid.height * size;
318 //if (r_refdef.vrect.height > vid.height - sb_lines)
319 // r_refdef.vrect.height = vid.height - sb_lines;
320 if (r_refdef.vrect.height > (int) vid.height)
321 r_refdef.vrect.height = vid.height;
322 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
324 r_refdef.vrect.y = 0;
326 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
328 r_refdef.fov_x = scr_fov.value;
329 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
340 void SCR_SizeUp_f (void)
342 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
343 vid.recalc_refdef = 1;
354 void SCR_SizeDown_f (void)
356 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
357 vid.recalc_refdef = 1;
360 //============================================================================
362 void gl_screen_start()
364 scr_ram = Draw_PicFromWad ("ram");
365 scr_net = Draw_PicFromWad ("net");
366 scr_turtle = Draw_PicFromWad ("turtle");
369 void gl_screen_shutdown()
373 void gl_screen_newmap()
382 void GL_Screen_Init (void)
385 Cvar_RegisterVariable (&scr_fov);
386 Cvar_RegisterVariable (&scr_viewsize);
387 Cvar_RegisterVariable (&scr_conspeed);
388 Cvar_RegisterVariable (&scr_showram);
389 Cvar_RegisterVariable (&scr_showturtle);
390 Cvar_RegisterVariable (&scr_showpause);
391 Cvar_RegisterVariable (&scr_centertime);
392 Cvar_RegisterVariable (&scr_printspeed);
393 Cvar_RegisterVariable (&showfps);
394 Cvar_RegisterVariable (&r_render);
400 // register our commands
402 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
403 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
404 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
406 scr_initialized = true;
408 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown, gl_screen_newmap);
418 void SCR_DrawRam (void)
420 if (!scr_showram.value)
426 Draw_Pic (32, 0, scr_ram);
434 void SCR_DrawTurtle (void)
438 if (!scr_showturtle.value)
441 if (cl.frametime < 0.1)
451 Draw_Pic (0, 0, scr_turtle);
459 void SCR_DrawNet (void)
461 if (realtime - cl.last_received_message < 0.3)
463 if (cls.demoplayback)
466 Draw_Pic (64, 0, scr_net);
474 void SCR_DrawPause (void)
478 if (!scr_showpause.value) // turn off for screenshots
484 pic = Draw_CachePic ("gfx/pause.lmp");
485 Draw_Pic ( (vid.width - pic->width)/2,
486 (vid.height - 48 - pic->height)/2, pic);
497 void SCR_DrawLoading (void)
501 if (!scr_drawloading)
504 pic = Draw_CachePic ("gfx/loading.lmp");
505 Draw_Pic ( (vid.width - pic->width)/2,
506 (vid.height - 48 - pic->height)/2, pic);
512 //=============================================================================
517 SCR_SetUpToDrawConsole
520 void SCR_SetUpToDrawConsole (void)
524 //if (scr_drawloading)
525 // return; // never a console with loading plaque
527 // decide on the height of the console
528 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
532 scr_conlines = vid.height; // full screen
533 scr_con_current = scr_conlines;
535 else if (key_dest == key_console)
536 scr_conlines = vid.height/2; // half screen
538 scr_conlines = 0; // none visible
540 if (scr_conlines < scr_con_current)
542 scr_con_current -= scr_conspeed.value*host_realframetime;
543 if (scr_conlines > scr_con_current)
544 scr_con_current = scr_conlines;
547 else if (scr_conlines > scr_con_current)
549 scr_con_current += scr_conspeed.value*host_realframetime;
550 if (scr_conlines < scr_con_current)
551 scr_con_current = scr_conlines;
560 void SCR_DrawConsole (void)
564 Con_DrawConsole (scr_con_current, true);
569 if (key_dest == key_game || key_dest == key_message)
570 Con_DrawNotify (); // only draw notify in game
576 ==============================================================================
580 ==============================================================================
588 void SCR_ScreenShot_f (void)
592 char checkname[MAX_OSPATH];
595 // find a file name to save it to
597 strcpy(filename,"dp0000.tga");
599 for (i=0 ; i<=9999 ; i++)
601 filename[2] = (i/1000)%10 + '0';
602 filename[3] = (i/ 100)%10 + '0';
603 filename[4] = (i/ 10)%10 + '0';
604 filename[5] = (i/ 1)%10 + '0';
605 sprintf (checkname, "%s/%s", com_gamedir, filename);
606 if (Sys_FileTime(checkname) == -1)
607 break; // file doesn't exist
611 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
615 buffer = qmalloc(glwidth*glheight*3);
616 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
617 Image_WriteTGARGB_preflipped(filename, glwidth, glheight, buffer);
620 Con_Printf ("Wrote %s\n", filename);
624 //=============================================================================
629 SCR_BeginLoadingPlaque
634 void SCR_BeginLoadingPlaque (void)
636 S_StopAllSounds (true);
638 // if (cls.state != ca_connected)
640 // if (cls.signon != SIGNONS)
643 // redraw with no console and the loading plaque
644 // Con_ClearNotify ();
645 // scr_centertime_off = 0;
646 // scr_con_current = 0;
648 scr_drawloading = true;
651 // scr_disabled_for_loading = true;
652 // scr_disabled_time = realtime;
663 void SCR_EndLoadingPlaque (void)
665 // scr_disabled_for_loading = false;
666 scr_drawloading = false;
671 //=============================================================================
673 char *scr_notifystring;
675 void SCR_DrawNotifyString (void)
681 start = scr_notifystring;
687 // scan the width of the line
688 for (l=0 ; l<40 ; l++)
689 if (start[l] == '\n' || !start[l])
691 x = (vid.width - l*8)/2;
692 // LordHavoc: speedup
693 // for (j=0 ; j<l ; j++, x+=8)
694 // Draw_Character (x, y, start[j]);
695 Draw_String (x, y, start, l);
699 while (*start && *start != '\n')
704 start++; // skip the \n
708 //=============================================================================
710 void DrawCrosshair(int num);
711 void GL_Set2D (void);
713 extern void SHOWLMP_drawall();
714 extern cvar_t contrast;
715 extern cvar_t brightness;
716 extern cvar_t gl_lightmode;
717 extern cvar_t r_speeds2;
719 void GL_BrightenScreen()
724 glDisable(GL_TEXTURE_2D);
726 f = bound(1.0f, brightness.value, 5.0f);
727 if (f != brightness.value)
728 Cvar_SetValue("brightness", f);
731 glBlendFunc (GL_DST_COLOR, GL_ONE);
732 glBegin (GL_TRIANGLES);
738 glColor3f (f-1, f-1, f-1);
739 glVertex2f (-5000, -5000);
740 glVertex2f (10000, -5000);
741 glVertex2f (-5000, 10000);
746 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
747 f = bound(0.2f, contrast.value, 1.0f);
748 if (f != contrast.value)
749 Cvar_SetValue("contrast", f);
750 if (contrast.value < 0.99f)
752 glBegin (GL_TRIANGLES);
753 glColor4f (1, 1, 1, 1-contrast.value);
754 glVertex2f (-5000, -5000);
755 glVertex2f (10000, -5000);
756 glVertex2f (-5000, 10000);
760 glEnable (GL_CULL_FACE);
761 glEnable (GL_DEPTH_TEST);
763 glEnable(GL_TEXTURE_2D);
770 This is called every frame, and can also be called explicitly to flush
773 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
777 void SCR_UpdateScreen (void)
779 double time1 = 0, time2;
782 time1 = Sys_FloatTime ();
784 if (scr_disabled_for_loading)
787 if (realtime - scr_disabled_time > 60)
789 scr_disabled_for_loading = false;
790 Con_Printf ("load failed.\n");
797 if (!scr_initialized || !con_initialized)
798 return; // not initialized yet
801 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
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();
840 SCR_CheckDrawCenterString();
845 DrawCrosshair(crosshair.value - 1);
847 if (cl.intermission == 1)
848 Sbar_IntermissionOverlay();
849 else if (cl.intermission == 2)
850 Sbar_FinaleOverlay();
855 // if (scr_drawloading)
856 // SCR_DrawLoading();
860 static double currtime;
864 newtime = Sys_FloatTime();
865 calc = (int) ((1.0 / (newtime - currtime)) + 0.5);
866 sprintf(temp, "%4i fps", calc);
868 Draw_String(vid.width - (8*8), vid.height - sb_lines - 8, temp, 9999);
873 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];
874 Draw_String(0, vid.height - sb_lines - 56, r_speeds2_string1, 80);
875 Draw_String(0, vid.height - sb_lines - 48, r_speeds2_string2, 80);
876 Draw_String(0, vid.height - sb_lines - 40, r_speeds2_string3, 80);
877 Draw_String(0, vid.height - sb_lines - 32, r_speeds2_string4, 80);
878 Draw_String(0, vid.height - sb_lines - 24, r_speeds2_string5, 80);
879 Draw_String(0, vid.height - sb_lines - 16, r_speeds2_string6, 80);
880 Draw_String(0, vid.height - sb_lines - 8, r_speeds2_string7, 80);
891 time2 = Sys_FloatTime ();
892 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);
897 // for profiling, this is separated