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 // force the status bar to redraw
276 //========================================
279 if (scr_viewsize.value < 30)
280 Cvar_Set ("viewsize","30");
281 if (scr_viewsize.value > 120)
282 Cvar_Set ("viewsize","120");
284 // bound field of view
285 if (scr_fov.value < 10)
286 Cvar_Set ("fov","10");
287 if (scr_fov.value > 170)
288 Cvar_Set ("fov","170");
290 // intermission is always full screen
294 size = scr_viewsize.value;
297 sb_lines = 0; // no status bar at all
298 else if (size >= 110)
299 sb_lines = 24; // no inventory
303 if (scr_viewsize.value >= 100.0)
309 size = scr_viewsize.value;
318 // LordHavoc: always fullyscreen rendering
319 h = vid.height/* - sb_lines*/;
321 r_refdef.vrect.width = vid.width * size;
322 if (r_refdef.vrect.width < 96)
324 size = 96.0 / r_refdef.vrect.width;
325 r_refdef.vrect.width = 96; // min for icons
328 r_refdef.vrect.height = vid.height * size;
329 //if (r_refdef.vrect.height > vid.height - sb_lines)
330 // r_refdef.vrect.height = vid.height - sb_lines;
331 if (r_refdef.vrect.height > (int) vid.height)
332 r_refdef.vrect.height = vid.height;
333 r_refdef.vrect.x = (vid.width - r_refdef.vrect.width)/2;
335 r_refdef.vrect.y = 0;
337 r_refdef.vrect.y = (h - r_refdef.vrect.height)/2;
339 r_refdef.fov_x = scr_fov.value;
340 r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);
351 void SCR_SizeUp_f (void)
353 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
354 vid.recalc_refdef = 1;
365 void SCR_SizeDown_f (void)
367 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
368 vid.recalc_refdef = 1;
371 //============================================================================
373 void gl_screen_start()
375 scr_ram = Draw_PicFromWad ("ram");
376 scr_net = Draw_PicFromWad ("net");
377 scr_turtle = Draw_PicFromWad ("turtle");
380 void gl_screen_shutdown()
389 void GL_Screen_Init (void)
392 Cvar_RegisterVariable (&scr_fov);
393 Cvar_RegisterVariable (&scr_viewsize);
394 Cvar_RegisterVariable (&scr_conspeed);
395 Cvar_RegisterVariable (&scr_showram);
396 Cvar_RegisterVariable (&scr_showturtle);
397 Cvar_RegisterVariable (&scr_showpause);
398 Cvar_RegisterVariable (&scr_centertime);
399 Cvar_RegisterVariable (&scr_printspeed);
400 Cvar_RegisterVariable (&showfps);
401 Cvar_RegisterVariable (&r_render);
407 // register our commands
409 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f);
410 Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
411 Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
413 scr_initialized = true;
415 R_RegisterModule("GL_Screen", gl_screen_start, gl_screen_shutdown);
425 void SCR_DrawRam (void)
427 if (!scr_showram.value)
433 Draw_Pic (32, 0, scr_ram);
441 void SCR_DrawTurtle (void)
445 if (!scr_showturtle.value)
448 if (host_frametime < 0.1)
458 Draw_Pic (0, 0, scr_turtle);
466 void SCR_DrawNet (void)
468 if (realtime - cl.last_received_message < 0.3)
470 if (cls.demoplayback)
473 Draw_Pic (64, 0, scr_net);
481 void SCR_DrawPause (void)
485 if (!scr_showpause.value) // turn off for screenshots
491 pic = Draw_CachePic ("gfx/pause.lmp");
492 Draw_Pic ( (vid.width - pic->width)/2,
493 (vid.height - 48 - pic->height)/2, pic);
503 void SCR_DrawLoading (void)
507 if (!scr_drawloading)
510 pic = Draw_CachePic ("gfx/loading.lmp");
511 Draw_Pic ( (vid.width - pic->width)/2,
512 (vid.height - 48 - pic->height)/2, pic);
517 //=============================================================================
522 SCR_SetUpToDrawConsole
525 void SCR_SetUpToDrawConsole (void)
529 //if (scr_drawloading)
530 // return; // never a console with loading plaque
532 // decide on the height of the console
533 con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
537 scr_conlines = vid.height; // full screen
538 scr_con_current = scr_conlines;
540 else if (key_dest == key_console)
541 scr_conlines = vid.height/2; // half screen
543 scr_conlines = 0; // none visible
545 if (scr_conlines < scr_con_current)
547 scr_con_current -= scr_conspeed.value*host_frametime;
548 if (scr_conlines > scr_con_current)
549 scr_con_current = scr_conlines;
552 else if (scr_conlines > scr_con_current)
554 scr_con_current += scr_conspeed.value*host_frametime;
555 if (scr_conlines < scr_con_current)
556 scr_con_current = scr_conlines;
565 void SCR_DrawConsole (void)
569 scr_copyeverything = 1;
570 Con_DrawConsole (scr_con_current, true);
575 if (key_dest == key_game || key_dest == key_message)
576 Con_DrawNotify (); // only draw notify in game
582 ==============================================================================
586 ==============================================================================
589 typedef struct _TargaHeader {
590 unsigned char id_length, colormap_type, image_type;
591 unsigned short colormap_index, colormap_length;
592 unsigned char colormap_size;
593 unsigned short x_origin, y_origin, width, height;
594 unsigned char pixel_size, attributes;
603 void SCR_ScreenShot_f (void)
607 char checkname[MAX_OSPATH];
610 // find a file name to save it to
612 strcpy(pcxname,"dp0000.tga");
614 for (i=0 ; i<=9999 ; i++)
616 pcxname[2] = (i/1000)%10 + '0';
617 pcxname[3] = (i/ 100)%10 + '0';
618 pcxname[4] = (i/ 10)%10 + '0';
619 pcxname[5] = (i/ 1)%10 + '0';
620 sprintf (checkname, "%s/%s", com_gamedir, pcxname);
621 if (Sys_FileTime(checkname) == -1)
622 break; // file doesn't exist
626 Con_Printf ("SCR_ScreenShot_f: Couldn't create a TGA file\n");
631 buffer = malloc(glwidth*glheight*3 + 18);
632 memset (buffer, 0, 18);
633 buffer[2] = 2; // uncompressed type
634 buffer[12] = glwidth&255;
635 buffer[13] = glwidth>>8;
636 buffer[14] = glheight&255;
637 buffer[15] = glheight>>8;
638 buffer[16] = 24; // pixel size
641 glReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 );
644 c = 18+glwidth*glheight*3;
645 for (i=18 ; i<c ; i+=3)
648 buffer[i] = buffer[i+2];
651 COM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );
654 Con_Printf ("Wrote %s\n", pcxname);
658 //=============================================================================
663 SCR_BeginLoadingPlaque
667 void SCR_BeginLoadingPlaque (void)
669 S_StopAllSounds (true);
671 if (cls.state != ca_connected)
673 if (cls.signon != SIGNONS)
676 // redraw with no console and the loading plaque
678 scr_centertime_off = 0;
681 scr_drawloading = true;
685 scr_drawloading = false;
687 scr_disabled_for_loading = true;
688 scr_disabled_time = realtime;
698 void SCR_EndLoadingPlaque (void)
700 scr_disabled_for_loading = false;
705 //=============================================================================
707 char *scr_notifystring;
708 qboolean scr_drawdialog;
710 void SCR_DrawNotifyString (void)
716 start = scr_notifystring;
722 // scan the width of the line
723 for (l=0 ; l<40 ; l++)
724 if (start[l] == '\n' || !start[l])
726 x = (vid.width - l*8)/2;
727 // LordHavoc: speedup
728 // for (j=0 ; j<l ; j++, x+=8)
729 // Draw_Character (x, y, start[j]);
730 Draw_String (x, y, start, l);
734 while (*start && *start != '\n')
739 start++; // skip the \n
747 Displays a text string in the center of the screen and waits for a Y or N
751 int SCR_ModalMessage (char *text)
753 if (cls.state == ca_dedicated)
756 scr_notifystring = text;
758 // draw a fresh screen
760 scr_drawdialog = true;
762 scr_drawdialog = false;
764 S_ClearBuffer (); // so dma doesn't loop current sound
768 key_count = -1; // wait for a key down and up
769 Sys_SendKeyEvents ();
770 } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);
775 return key_lastpress == 'y';
779 //=============================================================================
785 Brings the console down and fades the palettes back to normal
788 void SCR_BringDownConsole (void)
792 scr_centertime_off = 0;
794 for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)
797 cl.cshifts[0].percent = 0; // no area contents palette on next frame
800 void DrawCrosshair(int num);
801 void GL_Set2D (void);
803 extern void SHOWLMP_drawall();
804 extern cvar_t contrast;
805 extern cvar_t brightness;
806 extern cvar_t gl_lightmode;
808 void GL_BrightenScreen()
813 glDisable(GL_TEXTURE_2D);
815 f = brightness.value = bound(1.0f, brightness.value, 5.0f);
818 glBlendFunc (GL_DST_COLOR, GL_ONE);
819 glBegin (GL_TRIANGLES);
825 glColor3f (f-1, f-1, f-1);
826 glVertex2f (-5000, -5000);
827 glVertex2f (10000, -5000);
828 glVertex2f (-5000, 10000);
833 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
834 contrast.value = bound(0.2, contrast.value, 1.0);
835 if (contrast.value < 0.99f)
837 glBegin (GL_TRIANGLES);
838 glColor4f (1, 1, 1, 1-contrast.value);
839 glVertex2f (-5000, -5000);
840 glVertex2f (10000, -5000);
841 glVertex2f (-5000, 10000);
845 glEnable (GL_CULL_FACE);
846 glEnable (GL_DEPTH_TEST);
848 glEnable(GL_TEXTURE_2D);
855 This is called every frame, and can also be called explicitly to flush
858 LordHavoc: due to my rewrite of R_WorldNode, it no longer takes 256k of stack space :)
861 extern cvar_t gl_vertexarrays;
862 extern qboolean gl_arrays;
864 void SCR_UpdateScreen (void)
866 double time1 = 0, time2;
869 time1 = Sys_FloatTime ();
872 gl_vertexarrays.value = 0;
875 scr_copyeverything = 0;
877 if (scr_disabled_for_loading)
879 if (realtime - scr_disabled_time > 60)
881 scr_disabled_for_loading = false;
882 Con_Printf ("load failed.\n");
888 if (!scr_initialized || !con_initialized)
889 return; // not initialized yet
892 GL_BeginRendering (&glx, &gly, &glwidth, &glheight);
895 // determine size of refresh window
897 if (oldfov != scr_fov.value)
899 oldfov = scr_fov.value;
900 vid.recalc_refdef = true;
903 if (oldscreensize != scr_viewsize.value)
905 oldscreensize = scr_viewsize.value;
906 vid.recalc_refdef = true;
909 if (vid.recalc_refdef)
914 glClearColor(0,0,0,0);
915 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // LordHavoc: clear the screen (around the view as well)
919 // do 3D refresh drawing, and then update the screen
921 SCR_SetUpToDrawConsole ();
930 // Draw_FadeScreen ();
931 SCR_DrawNotifyString ();
932 scr_copyeverything = true;
934 else if (scr_drawloading)
939 else if (cl.intermission == 1 && key_dest == key_game)
941 Sbar_IntermissionOverlay ();
943 else if (cl.intermission == 2 && key_dest == key_game)
945 Sbar_FinaleOverlay ();
946 SCR_CheckDrawCenterString ();
951 DrawCrosshair(crosshair.value);
957 SCR_CheckDrawCenterString ();
966 static double currtime;
970 newtime = Sys_FloatTime();
971 calc = (int) (100.0 / (newtime - currtime));
972 sprintf(temp, "% 4i.%02i fps", calc / 100, calc % 100);
974 Draw_String(vid.width - (12*8), 0, temp, 9999);
985 time2 = Sys_FloatTime ();
986 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);
991 // for profiling, this is seperated