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};
93 extern cvar_t crosshair;
95 qboolean scr_initialized; // ready to draw
108 extern viddef_t vid; // global video state
110 qboolean scr_disabled_for_loading;
111 qboolean scr_drawloading;
112 float scr_disabled_time;
114 void SCR_ScreenShot_f (void);
117 ===============================================================================
121 ===============================================================================
124 char scr_centerstring[1024];
125 float scr_centertime_start; // for slow victory printing
126 float scr_centertime_off;
127 int scr_center_lines;
129 int scr_erase_center;
135 Called for important messages that should stay in the center of the screen
139 void SCR_CenterPrint (char *str)
141 strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
142 scr_centertime_off = scr_centertime.value;
143 scr_centertime_start = cl.time;
145 // count the number of lines for centering
146 scr_center_lines = 1;
156 void SCR_DrawCenterString (void)
163 // the finale prints the characters one at a time
165 remaining = scr_printspeed.value * (cl.time - scr_centertime_start);
169 scr_erase_center = 0;
170 start = scr_centerstring;
172 if (scr_center_lines <= 4)
179 // scan the width of the line
180 for (l=0 ; l<40 ; l++)
181 if (start[l] == '\n' || !start[l])
183 x = (vid.width - l*8)/2;
184 // LordHavoc: speedup
189 Draw_String(x, y, start, l);
195 for (j=0 ; j<l ; j++, x+=8)
197 Draw_Character (x, y, start[j]);
205 while (*start && *start != '\n')
210 start++; // skip the \n
214 void SCR_CheckDrawCenterString (void)
217 if (scr_center_lines > scr_erase_lines)
218 scr_erase_lines = scr_center_lines;
220 scr_centertime_off -= host_frametime;
222 if (scr_centertime_off <= 0 && !cl.intermission)
224 if (key_dest != key_game)
227 SCR_DrawCenterString ();
230 //=============================================================================
237 float CalcFov (float fov_x, float width, float height)
242 if (fov_x < 1 || fov_x > 179)
243 Sys_Error ("Bad fov: %f", fov_x);
245 x = width/tan(fov_x/360*M_PI);
258 Must be called whenever vid changes
262 static void SCR_CalcRefdef (void)
266 qboolean full = false;
269 scr_fullupdate = 0; // force a background redraw
270 vid.recalc_refdef = 0;
272 // force the status bar to redraw
275 //========================================
278 if (scr_viewsize.value < 30)
279 Cvar_Set ("viewsize","30");
280 if (scr_viewsize.value > 120)
281 Cvar_Set ("viewsize","120");
283 // bound field of view
284 if (scr_fov.value < 10)
285 Cvar_Set ("fov","10");
286 if (scr_fov.value > 170)
287 Cvar_Set ("fov","170");
289 // intermission is always full screen
293 size = scr_viewsize.value;
296 sb_lines = 0; // no status bar at all
297 else if (size >= 110)
298 sb_lines = 24; // no inventory
302 if (scr_viewsize.value >= 100.0)
308 size = scr_viewsize.value;
317 // LordHavoc: always fullyscreen rendering
318 h = vid.height/* - sb_lines*/;
320 r_refdef.vrect.width = vid.width * size;
321 if (r_refdef.vrect.width < 96)
323 size = 96.0 / r_refdef.vrect.width;
324 r_refdef.vrect.width = 96; // min for icons
327 r_refdef.vrect.height = vid.height * size;
328 //if (r_refdef.vrect.height > vid.height - sb_lines)
329 // r_refdef.vrect.height = vid.height - sb_lines;
330 if (r_refdef.vrect.height > (int) vid.height)
331 r_refdef.vrect.height = vid.height;
332 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
334 r_refdef.vrect.y = 0;
336 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
338 r_refdef.fov_x = scr_fov.value;
339 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
350 void SCR_SizeUp_f (void)
352 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
353 vid.recalc_refdef = 1;
364 void SCR_SizeDown_f (void)
366 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
367 vid.recalc_refdef = 1;
370 //============================================================================
372 void gl_screen_start()
374 scr_ram = Draw_PicFromWad ("ram");
375 scr_net = Draw_PicFromWad ("net");
376 scr_turtle = Draw_PicFromWad ("turtle");
379 void gl_screen_shutdown()
388 void GL_Screen_Init (void)
391 Cvar_RegisterVariable (&scr_fov);
392 Cvar_RegisterVariable (&scr_viewsize);
393 Cvar_RegisterVariable (&scr_conspeed);
394 Cvar_RegisterVariable (&scr_showram);
395 Cvar_RegisterVariable (&scr_showturtle);
396 Cvar_RegisterVariable (&scr_showpause);
397 Cvar_RegisterVariable (&scr_centertime);
398 Cvar_RegisterVariable (&scr_printspeed);
399 Cvar_RegisterVariable (&showfps);
402 // register our commands
404 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
405 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
406 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
408 scr_initialized = true;
410 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown);
420 void SCR_DrawRam (void)
422 if (!scr_showram.value)
428 Draw_Pic (32, 0, scr_ram);
436 void SCR_DrawTurtle (void)
440 if (!scr_showturtle.value)
443 if (host_frametime < 0.1)
453 Draw_Pic (0, 0, scr_turtle);
461 void SCR_DrawNet (void)
463 if (realtime - cl.last_received_message < 0.3)
465 if (cls.demoplayback)
468 Draw_Pic (64, 0, scr_net);
476 void SCR_DrawPause (void)
480 if (!scr_showpause.value) // turn off for screenshots
486 pic = Draw_CachePic ("gfx/pause.lmp");
487 Draw_Pic ( (vid.width - pic->width)/2,
488 (vid.height - 48 - pic->height)/2, pic);
498 void SCR_DrawLoading (void)
502 if (!scr_drawloading)
505 pic = Draw_CachePic ("gfx/loading.lmp");
506 Draw_Pic ( (vid.width - pic->width)/2,
507 (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_frametime;
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_frametime;
550 if (scr_conlines < scr_con_current)
551 scr_con_current = scr_conlines;
560 void SCR_DrawConsole (void)
564 scr_copyeverything = 1;
565 Con_DrawConsole (scr_con_current, true);
570 if (key_dest == key_game || key_dest == key_message)
571 Con_DrawNotify (); // only draw notify in game
577 ==============================================================================
581 ==============================================================================
584 typedef struct _TargaHeader {
585 unsigned char id_length, colormap_type, image_type;
586 unsigned short colormap_index, colormap_length;
587 unsigned char colormap_size;
588 unsigned short x_origin, y_origin, width, height;
589 unsigned char pixel_size, attributes;
598 void SCR_ScreenShot_f (void)
602 char checkname[MAX_OSPATH];
605 // find a file name to save it to
607 strcpy(pcxname,"dp0000.tga");
609 for (i=0 ; i<=9999 ; i++)
611 pcxname[2] = (i/1000)%10 + '0';
612 pcxname[3] = (i/ 100)%10 + '0';
613 pcxname[4] = (i/ 10)%10 + '0';
614 pcxname[5] = (i/ 1)%10 + '0';
615 sprintf (checkname, "%s/%s", com_gamedir, pcxname);
616 if (Sys_FileTime(checkname) == -1)
617 break; // file doesn't exist
621 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
626 buffer = malloc(glwidth*glheight*3 + 18);
627 memset (buffer, 0, 18);
628 buffer[2] = 2; // uncompressed type
629 buffer[12] = glwidth&255;
630 buffer[13] = glwidth>>8;
631 buffer[14] = glheight&255;
632 buffer[15] = glheight>>8;
633 buffer[16] = 24; // pixel size
635 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
638 c = 18+glwidth*glheight*3;
639 for (i=18 ; i<c ; i+=3)
642 buffer[i] = buffer[i+2];
645 COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
648 Con_Printf ("Wrote %s\n", pcxname);
652 //=============================================================================
657 SCR_BeginLoadingPlaque
661 void SCR_BeginLoadingPlaque (void)
663 S_StopAllSounds (true);
665 if (cls.state != ca_connected)
667 if (cls.signon != SIGNONS)
670 // redraw with no console and the loading plaque
672 scr_centertime_off = 0;
675 scr_drawloading = true;
679 scr_drawloading = false;
681 scr_disabled_for_loading = true;
682 scr_disabled_time = realtime;
692 void SCR_EndLoadingPlaque (void)
694 scr_disabled_for_loading = false;
699 //=============================================================================
701 char *scr_notifystring;
702 qboolean scr_drawdialog;
704 void SCR_DrawNotifyString (void)
710 start = scr_notifystring;
716 // scan the width of the line
717 for (l=0 ; l<40 ; l++)
718 if (start[l] == '\n' || !start[l])
720 x = (vid.width - l*8)/2;
721 // LordHavoc: speedup
722 // for (j=0 ; j<l ; j++, x+=8)
723 // Draw_Character (x, y, start[j]);
724 Draw_String (x, y, start, l);
728 while (*start && *start != '\n')
733 start++; // skip the \n
741 Displays a text string in the center of the screen and waits for a Y or N
745 int SCR_ModalMessage (char *text)
747 if (cls.state == ca_dedicated)
750 scr_notifystring = text;
752 // draw a fresh screen
754 scr_drawdialog = true;
756 scr_drawdialog = false;
758 S_ClearBuffer (); // so dma doesn't loop current sound
762 key_count = -1; // wait for a key down and up
763 Sys_SendKeyEvents ();
764 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
769 return key_lastpress == 'y';
773 //=============================================================================
779 Brings the console down and fades the palettes back to normal
782 void SCR_BringDownConsole (void)
786 scr_centertime_off = 0;
788 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
791 cl.cshifts[0].percent = 0; // no area contents palette on next frame
794 void DrawCrosshair(int num);
795 void GL_Set2D (void);
797 extern void SHOWLMP_drawall();
798 extern cvar_t contrast;
799 extern cvar_t brightness;
800 extern cvar_t gl_lightmode;
802 void GL_BrightenScreen()
805 glDisable(GL_TEXTURE_2D);
807 f = brightness.value = bound(1.0f, brightness.value, 5.0f);
810 glBlendFunc (GL_DST_COLOR, GL_ONE);
811 glBegin (GL_TRIANGLES);
817 glColor3f (f-1, f-1, f-1);
818 glVertex2f (-5000, -5000);
819 glVertex2f (10000, -5000);
820 glVertex2f (-5000, 10000);
825 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
826 contrast.value = bound(0.2, contrast.value, 1.0);
827 if (contrast.value < 0.99f)
829 glBegin (GL_TRIANGLES);
830 glColor4f (1, 1, 1, 1-contrast.value);
831 glVertex2f (-5000, -5000);
832 glVertex2f (10000, -5000);
833 glVertex2f (-5000, 10000);
837 glEnable (GL_CULL_FACE);
838 glEnable (GL_DEPTH_TEST);
840 glEnable(GL_TEXTURE_2D);
847 This is called every frame, and can also be called explicitly to flush
850 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
853 extern cvar_t gl_vertexarrays;
854 extern qboolean gl_arrays;
856 void SCR_UpdateScreen (void)
858 double time1 = 0, time2;
861 time1 = Sys_FloatTime ();
864 gl_vertexarrays.value = 0;
867 scr_copyeverything = 0;
869 if (scr_disabled_for_loading)
871 if (realtime - scr_disabled_time > 60)
873 scr_disabled_for_loading = false;
874 Con_Printf ("load failed.\n");
880 if (!scr_initialized || !con_initialized)
881 return; // not initialized yet
884 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
887 // determine size of refresh window
889 if (oldfov != scr_fov.value)
891 oldfov = scr_fov.value;
892 vid.recalc_refdef = true;
895 if (oldscreensize != scr_viewsize.value)
897 oldscreensize = scr_viewsize.value;
898 vid.recalc_refdef = true;
901 if (vid.recalc_refdef)
904 glClearColor(0,0,0,0);
905 glClear (GL_COLOR_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
908 // do 3D refresh drawing, and then update the screen
910 SCR_SetUpToDrawConsole ();
919 // Draw_FadeScreen ();
920 SCR_DrawNotifyString ();
921 scr_copyeverything = true;
923 else if (scr_drawloading)
928 else if (cl.intermission == 1 && key_dest == key_game)
930 Sbar_IntermissionOverlay ();
932 else if (cl.intermission == 2 && key_dest == key_game)
934 Sbar_FinaleOverlay ();
935 SCR_CheckDrawCenterString ();
940 DrawCrosshair(crosshair.value);
946 SCR_CheckDrawCenterString ();
955 static double currtime;
959 newtime = Sys_FloatTime();
960 calc = (int) (100.0 / (newtime - currtime));
961 sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
963 Draw_String(vid.width - (12*8), 0, temp, 9999);
974 time2 = Sys_FloatTime ();
975 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);
980 // for profiling, this is seperated