ref: 191f0d455fbc787c63e31bb58b649dd9d0828bea
dir: /screen.c/
#include "quakedef.h" float scr_con_current; static float scr_conlines; // lines of console to display static float oldscreensize, oldfov; cvar_t scr_viewsize = {"viewsize","100", true}; static cvar_t scr_fov = {"fov","90",true}; // 10 - 170 static cvar_t scr_conspeed = {"scr_conspeed","300",true}; static cvar_t scr_centertime = {"scr_centertime","2"}; static cvar_t scr_showram = {"showram","1"}; static cvar_t scr_showturtle = {"showturtle","0"}; static cvar_t scr_showpause = {"showpause","1"}; static cvar_t scr_printspeed = {"scr_printspeed","8"}; static cvar_t scr_showfps = {"showfps","0", true}; static bool scr_initialized; // ready to draw static qpic_t *scr_net, *scr_turtle; int scr_fullupdate; static int clearconsole; int clearnotify; viddef_t vid; // global video state vrect_t scr_vrect; bool scr_disabled_for_loading; static bool scr_drawloading; static float scr_disabled_time; /* =============================================================================== CENTER PRINTING =============================================================================== */ float scr_centertime_off; static char scr_centerstring[1024]; static float scr_centertime_start; // for slow victory printing static int scr_center_lines; static int scr_erase_lines; static int scr_erase_center; /* ============== SCR_CenterPrint Called for important messages that should stay in the center of the screen for a few moments ============== */ void SCR_CenterPrint (char *str) { strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); scr_centertime_off = scr_centertime.value; scr_centertime_start = cl.time; // count the number of lines for centering scr_center_lines = 1; while (*str) { if (*str == '\n') scr_center_lines++; str++; } } static void SCR_EraseCenterString (void) { int y; if (scr_erase_center++ > vid.numpages) { scr_erase_lines = 0; return; } if (scr_center_lines <= 4) y = vid.height*0.35; else y = 48; Draw_TileClear (0, y,vid.width, 8*scr_erase_lines); } static void SCR_DrawCenterString (void) { char *start; int l; int j; int x, y; int remaining; // the finale prints the characters one at a time if (cl.intermission) remaining = scr_printspeed.value * (cl.time - scr_centertime_start); else remaining = Q_MAXINT; scr_erase_center = 0; start = scr_centerstring; if (scr_center_lines <= 4) y = vid.height*0.35; else y = 48; do { // scan the width of the line for (l=0 ; l<40 ; l++) if (start[l] == '\n' || !start[l]) break; x = (vid.width - l*8)/2; for (j=0 ; j<l ; j++, x+=8) { Draw_Character (x, y, start[j]); if (!remaining--) return; } y += 8; while (*start && *start != '\n') start++; if (!*start) break; start++; // skip the \n } while (1); } static void SCR_CheckDrawCenterString (void) { if (scr_center_lines > scr_erase_lines) scr_erase_lines = scr_center_lines; scr_centertime_off -= host_frametime; if (scr_centertime_off <= 0 && !cl.intermission) return; if (key_dest != key_game) return; SCR_DrawCenterString (); } //============================================================================= static float CalcFov(float fov, float a, float b) { float v; fov = clamp(fov, 1, 179); v = a / tanf(fov / 360 * M_PI); return atanf(b / v) * 360.0 / M_PI; } /* ================= SCR_CalcRefdef Must be called whenever vid changes Internal use only ================= */ static void SCR_CalcRefdef (void) { vrect_t vrect; float size; scr_fullupdate = 0; // force a background redraw vid.recalc_refdef = false; // force the status bar to redraw Sbar_Changed (); //======================================== // bound viewsize if (scr_viewsize.value < 100) setcvar ("viewsize","100"); if (scr_viewsize.value > 120) setcvar ("viewsize","120"); // bound field of view if (scr_fov.value < 10) setcvar ("fov","10"); if (scr_fov.value > 170) setcvar ("fov","170"); r_refdef.fov_y = CalcFov(scr_fov.value, 640, 432); // 480→432 adjusted for a status bar r_refdef.fov_x = CalcFov(r_refdef.fov_y, r_refdef.vrect.height, r_refdef.vrect.width); scr_vrect = r_refdef.vrect; // intermission is always full screen if (cl.intermission) size = 120; else size = scr_viewsize.value; if (size >= 120) sb_lines = 0; // no status bar at all else if (size >= 110) sb_lines = 24; // no inventory else sb_lines = 24+16+8; // these calculations mirror those in R_Init() for r_refdef, but take no // account of water warping vrect.x = 0; vrect.y = 0; vrect.width = vid.width; vrect.height = vid.height; R_SetVrect (&vrect, &scr_vrect, sb_lines); // guard against going from one mode to another that's less than half the // vertical resolution if (scr_con_current > vid.height) scr_con_current = vid.height; // notify the refresh of the change R_ViewChanged (&vrect, sb_lines, vid.aspect); } /* ================= SCR_SizeUp_f Keybinding command ================= */ static void SCR_SizeUp_f (void) { setcvarv ("viewsize",scr_viewsize.value+10); vid.recalc_refdef = true; } /* ================= SCR_SizeDown_f Keybinding command ================= */ static void SCR_SizeDown_f (void) { setcvarv ("viewsize",scr_viewsize.value-10); vid.recalc_refdef = true; } void SCR_Init (void) { Cvar_RegisterVariable (&scr_fov); Cvar_RegisterVariable (&scr_viewsize); Cvar_RegisterVariable (&scr_conspeed); Cvar_RegisterVariable (&scr_showram); Cvar_RegisterVariable (&scr_showturtle); Cvar_RegisterVariable (&scr_showpause); Cvar_RegisterVariable (&scr_centertime); Cvar_RegisterVariable (&scr_printspeed); Cvar_RegisterVariable(&scr_showfps); Cmd_AddCommand ("sizeup",SCR_SizeUp_f); Cmd_AddCommand ("sizedown",SCR_SizeDown_f); scr_net = Draw_PicFromWad ("net"); scr_turtle = Draw_PicFromWad ("turtle"); scr_initialized = true; } /* ============== SCR_DrawTurtle ============== */ static void SCR_DrawTurtle (void) { static int count; if (!scr_showturtle.value) return; if (host_frametime < 0.1) { count = 0; return; } count++; if (count < 3) return; Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); } static void SCR_DrawFPS (void) { static uvlong lastframetime; static int lastcnt, fps; uvlong t; int n; char s[16]; if(!scr_showfps.value) return; t = nanosec(); if((t - lastframetime) >= 1000000000ULL){ fps = host_framecount - lastcnt; lastcnt = host_framecount; lastframetime = t; } n = snprint(s, sizeof(s), "%d", fps); Draw_String(vid.width - n*8, 0, s); } /* ============== SCR_DrawNet ============== */ static void SCR_DrawNet (void) { if (realtime - cl.last_received_message < 0.3) return; if (cls.demoplayback) return; Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net); } /* ============== DrawPause ============== */ static void SCR_DrawPause (void) { qpic_t *pic; if (!scr_showpause.value) // turn off for screenshots return; if (!cl.paused) return; pic = Draw_CachePic ("gfx/pause.lmp"); Draw_Pic ( (vid.width - pic->width)/2, (vid.height - 48 - pic->height)/2, pic); } /* ============== SCR_DrawLoading ============== */ static void SCR_DrawLoading (void) { qpic_t *pic; if (!scr_drawloading) return; pic = Draw_CachePic ("gfx/loading.lmp"); Draw_Pic ( (vid.width - pic->width)/2, (vid.height - 48 - pic->height)/2, pic); } //============================================================================= /* ================== SCR_SetUpToDrawConsole ================== */ static void SCR_SetUpToDrawConsole (void) { Con_CheckResize (); if (scr_drawloading) return; // never a console with loading plaque // decide on the height of the console con_forcedup = !cl.worldmodel || cls.signon != SIGNONS; if (con_forcedup) { scr_conlines = vid.height; // full screen scr_con_current = scr_conlines; } else if (key_dest == key_console) scr_conlines = vid.height/2; // half screen else scr_conlines = 0; // none visible if (scr_conlines < scr_con_current) { scr_con_current -= scr_conspeed.value*host_frametime; if (scr_conlines > scr_con_current) scr_con_current = scr_conlines; } else if (scr_conlines > scr_con_current) { scr_con_current += scr_conspeed.value*host_frametime; if (scr_conlines < scr_con_current) scr_con_current = scr_conlines; } if (clearconsole++ < vid.numpages) { Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current); Sbar_Changed (); } else if (clearnotify++ < vid.numpages) { Draw_TileClear (0,0,vid.width, con_notifylines); } else con_notifylines = 0; } /* ================== SCR_DrawConsole ================== */ static void SCR_DrawConsole (void) { if (scr_con_current) { Con_DrawConsole (scr_con_current, true); clearconsole = 0; } else { if (key_dest == key_game || key_dest == key_message) Con_DrawNotify (); // only draw notify in game } } /* =============== SCR_BeginLoadingPlaque ================ */ void SCR_BeginLoadingPlaque (void) { stopallsfx(); if (cls.state != ca_connected) return; if (cls.signon != SIGNONS) return; // redraw with no console and the loading plaque Con_ClearNotify (); scr_centertime_off = 0; scr_con_current = 0; scr_drawloading = true; scr_fullupdate = 0; Sbar_Changed (); SCR_UpdateScreen(false); scr_drawloading = false; scr_disabled_for_loading = true; scr_disabled_time = realtime; scr_fullupdate = 0; } /* =============== SCR_EndLoadingPlaque ================ */ void SCR_EndLoadingPlaque (void) { scr_disabled_for_loading = false; scr_fullupdate = 0; Con_ClearNotify (); } //============================================================================= static char *scr_notifystring; static void SCR_DrawNotifyString (void) { char *start; int l; int j; int x, y; start = scr_notifystring; y = vid.height*0.35; do { // scan the width of the line for (l=0 ; l<40 ; l++) if (start[l] == '\n' || !start[l]) break; x = (vid.width - l*8)/2; for (j=0 ; j<l ; j++, x+=8) Draw_Character (x, y, start[j]); y += 8; while (*start && *start != '\n') start++; if (!*start) break; start++; // skip the \n } while (1); } /* ================== SCR_ModalMessage Displays a text string in the center of the screen and waits for a Y or N keypress. ================== */ int SCR_ModalMessage (char *text) { if (cls.state == ca_dedicated) return true; scr_notifystring = text; // draw a fresh screen scr_fullupdate = 0; SCR_UpdateScreen (true); do { key_count = -1; // wait for a key down and up Sys_SendKeyEvents (); } while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE); scr_fullupdate = 0; SCR_UpdateScreen (false); return key_lastpress == 'y'; } //============================================================================= /* =============== SCR_BringDownConsole Brings the console down and fades the palettes back to normal ================ */ void SCR_BringDownConsole (void) { int i; scr_centertime_off = 0; for (i=0 ; i<20 && scr_conlines != scr_con_current ; i++) SCR_UpdateScreen(false); cl.cshifts[0].percent = 0; // no area contents palette on next frame setpal(host_basepal); } /* ================== SCR_UpdateScreen This is called every frame, and can also be called explicitly to flush text to the screen. WARNING: be very careful calling this from elsewhere, because the refresh needs almost the entire 256k of stack space! ================== */ void SCR_UpdateScreen (bool drawdialog) { static float oldlcd_x; if (scr_disabled_for_loading) { if (realtime - scr_disabled_time > 60) { scr_disabled_for_loading = false; Con_Printf ("load failed.\n"); } else return; } if (cls.state == ca_dedicated) return; // stdout only if (!scr_initialized || !con_initialized) return; // not initialized yet // check for vid changes if (oldfov != scr_fov.value) { oldfov = scr_fov.value; vid.recalc_refdef = true; } if (oldlcd_x != lcd_x.value) { oldlcd_x = lcd_x.value; vid.recalc_refdef = true; } if (oldscreensize != scr_viewsize.value) { oldscreensize = scr_viewsize.value; vid.recalc_refdef = true; } if (vid.recalc_refdef) { // something changed, so reorder the screen SCR_CalcRefdef (); } // do 3D refresh drawing, and then update the screen if (scr_fullupdate++ < vid.numpages) { // clear the entire screen Draw_TileClear (0,0,vid.width,vid.height); Sbar_Changed (); } SCR_SetUpToDrawConsole (); SCR_EraseCenterString (); // for linear writes all the time V_RenderView (); if (drawdialog) { Sbar_Draw (); Draw_FadeScreen (); SCR_DrawNotifyString (); } else if (scr_drawloading) { SCR_DrawLoading (); Sbar_Draw (); } else if (cl.intermission == 1 && key_dest == key_game) { Sbar_IntermissionOverlay (); } else if (cl.intermission == 2 && key_dest == key_game) { Sbar_FinaleOverlay (); SCR_CheckDrawCenterString (); } else if (cl.intermission == 3 && key_dest == key_game) { SCR_CheckDrawCenterString (); } else { SCR_DrawNet (); SCR_DrawTurtle (); SCR_DrawPause (); SCR_CheckDrawCenterString (); Sbar_Draw (); SCR_DrawConsole (); M_Draw (); } SCR_DrawFPS(); V_UpdatePalette (); flipfb(); }