#include "quakedef.h" static float scr_conlines; // lines of console to displaystatic float oldfov;static cvar_t scr_conspeed = {"scr_conspeed", "900", 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 cvar_t v_maxfps = {"v_maxfps", "0", true}; cvar_t scr_viewsize = {"viewsize", "100", true};cvar_t scr_fov = {"fov", "90", true}; // 10 - 170 static bool scr_initialized; // ready to drawstatic qpic_t *scr_net, *scr_turtle;static int clearconsole;static bool scr_drawloading;static double scr_disabled_time;static u64int scr_framecount;double scr_frametime, scr_oldtime; int scr_fullupdate;int clearnotify;viddef_t vid; // global video statevrect_t scr_vrect;bool scr_disabled_for_loading;float scr_con_current; float scr_centertime_off;static char scr_centerstring[1024];static float scr_centertime_start; // for slow victory printingstatic int scr_center_lines;static int scr_erase_lines;static int scr_erase_center;static const char *scr_notifystring; /* * Called for important messages that should stay in the center of the screen * for a few moments */voidSCR_CenterPrint(const 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 voidSCR_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 voidSCR_DrawCenterString(void){ const char *start; int l, j, x, y, 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 voidSCR_CheckDrawCenterString(void){ if(scr_center_lines > scr_erase_lines) scr_erase_lines = scr_center_lines; scr_centertime_off -= scr_frametime; if(scr_centertime_off <= 0 && !cl.intermission) return; if(key_dest != key_game) return; SCR_DrawCenterString();} static floatCalcFov(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;} /* Must be called whenever vid changes */static voidSCR_CalcRefdef(void){ vrect_t vrect; float size; scr_fullupdate = 0; // force a background redraw vid.recalc_refdef = false; // bound viewsize if(scr_viewsize.value < 100) setcvar("viewsize", "100"); else if(scr_viewsize.value > 120) setcvar("viewsize", "120"); // bound field of view if(scr_fov.value < 10) setcvar("fov", "10"); else if(scr_fov.value > 170) setcvar("fov", "170"); scr_vrect = r_refdef.vrect; // intermission is always full screen size = cl.intermission ? 120 : 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; // adapt 4:3 fov to current aspect (taken from yquake2) r_refdef.fov_x = atanf( tanf(scr_fov.value / 360.0 * M_PI) * ((float)r_refdef.vrect.width / (float)r_refdef.vrect.height * 0.75) ) / M_PI * 360.0; r_refdef.fov_y = CalcFov(r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); // 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; // 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, vid.aspect);} static voidSCR_SizeUp_f(cmd_t *c){ USED(c); setcvarv("viewsize", scr_viewsize.value + 10); vid.recalc_refdef = true;} static voidSCR_SizeDown_f(cmd_t *c){ USED(c); setcvarv("viewsize", scr_viewsize.value - 10); vid.recalc_refdef = true;} voidSCR_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); Cvar_RegisterVariable(&v_maxfps); 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;} static voidSCR_DrawTurtle(void){ static int count; if(!scr_showturtle.value) return; if(scr_frametime < 0.1) { count = 0; return; } count++; if(count < 3) return; Draw_Pic(scr_vrect.x, scr_vrect.y, scr_turtle);} static voidSCR_DrawFPS(void){ static u64int lastframetime; static int lastcnt, fps; u64int t; int n; char s[16]; if(!scr_showfps.value) return; t = nanosec(); if((t - lastframetime) >= 1000000000ULL) { fps = scr_framecount - lastcnt; lastcnt = scr_framecount; lastframetime = t; } n = snprint(s, sizeof(s), "%d", fps); Draw_String(vid.width - n * 8, 0, s);} static voidSCR_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);} static voidSCR_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);} static voidSCR_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);} static voidSCR_SetUpToDrawConsole(void){ float dt; 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 dt = scr_conspeed.value * scr_frametime * vid.height / MINHEIGHT; if(scr_conlines < scr_con_current) { scr_con_current -= dt; if(scr_conlines > scr_con_current) scr_con_current = scr_conlines; } else if(scr_conlines > scr_con_current) { scr_con_current += dt; 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); else if(clearnotify++ < vid.numpages) Draw_TileClear(0, 0, vid.width, con_notifylines); else con_notifylines = 0;} static voidSCR_DrawConsole(void){ if(scr_con_current) Con_DrawConsole(scr_con_current, true); else if(key_dest == key_game || key_dest == key_message) Con_DrawNotify(); // only draw notify in game clearconsole = 0;} voidSCR_BeginLoadingPlaque(void){ stopallsfx(nil); 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; SCR_UpdateScreen(false); scr_drawloading = false; scr_disabled_for_loading = true; scr_disabled_time = realtime; scr_fullupdate = 0;} voidSCR_EndLoadingPlaque(void){ scr_disabled_for_loading = false; scr_fullupdate = 0; Con_ClearNotify();} static voidSCR_DrawNotifyString(void){ const char *start; int l, j, 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);} /* * Displays a text string in the center of the screen and waits for a Y or N keypress. */boolSCR_ModalMessage(const 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';} /* Brings the console down and fades the palettes back to normal */voidSCR_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} static boolboundfps(void){ static double oldtime; double time, fpsmax = v_maxfps.value; if(fpsmax < 1 || fpsmax > 999) return false; time = dtime(); if(time - oldtime < 1.0 / fpsmax) return true; oldtime = time; return false;} /* * This is called every frame, and can also be called explicitly to flush * text to the screen. */voidSCR_UpdateScreen(bool drawdialog){ double t; if(scr_disabled_for_loading) {Lines 1–500 of 573. Load more
#include "quakedef.h" static float scr_conlines; // lines of console to display static float oldfov; static cvar_t scr_conspeed = {"scr_conspeed", "900", 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 cvar_t v_maxfps = {"v_maxfps", "0", true}; cvar_t scr_viewsize = {"viewsize", "100", true}; cvar_t scr_fov = {"fov", "90", true}; // 10 - 170 static bool scr_initialized; // ready to draw static qpic_t *scr_net, *scr_turtle; static int clearconsole; static bool scr_drawloading; static double scr_disabled_time; static u64int scr_framecount; double scr_frametime, scr_oldtime; int scr_fullupdate; int clearnotify; viddef_t vid; // global video state vrect_t scr_vrect; bool scr_disabled_for_loading; float scr_con_current; 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; static const char *scr_notifystring; /* * Called for important messages that should stay in the center of the screen * for a few moments */ void SCR_CenterPrint(const 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) { const char *start; int l, j, x, y, 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 -= scr_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; } /* Must be called whenever vid changes */ static void SCR_CalcRefdef(void) { vrect_t vrect; float size; scr_fullupdate = 0; // force a background redraw vid.recalc_refdef = false; // bound viewsize if(scr_viewsize.value < 100) setcvar("viewsize", "100"); else if(scr_viewsize.value > 120) setcvar("viewsize", "120"); // bound field of view if(scr_fov.value < 10) setcvar("fov", "10"); else if(scr_fov.value > 170) setcvar("fov", "170"); scr_vrect = r_refdef.vrect; // intermission is always full screen size = cl.intermission ? 120 : 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; // adapt 4:3 fov to current aspect (taken from yquake2) r_refdef.fov_x = atanf( tanf(scr_fov.value / 360.0 * M_PI) * ((float)r_refdef.vrect.width / (float)r_refdef.vrect.height * 0.75) ) / M_PI * 360.0; r_refdef.fov_y = CalcFov(r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); // 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; // 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, vid.aspect); } static void SCR_SizeUp_f(cmd_t *c) { USED(c); setcvarv("viewsize", scr_viewsize.value + 10); vid.recalc_refdef = true; } static void SCR_SizeDown_f(cmd_t *c) { USED(c); 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); Cvar_RegisterVariable(&v_maxfps); 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; } static void SCR_DrawTurtle(void) { static int count; if(!scr_showturtle.value) return; if(scr_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 u64int lastframetime; static int lastcnt, fps; u64int t; int n; char s[16]; if(!scr_showfps.value) return; t = nanosec(); if((t - lastframetime) >= 1000000000ULL) { fps = scr_framecount - lastcnt; lastcnt = scr_framecount; lastframetime = t; } n = snprint(s, sizeof(s), "%d", fps); Draw_String(vid.width - n * 8, 0, s); } 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); } 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); } 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); } static void SCR_SetUpToDrawConsole(void) { float dt; 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 dt = scr_conspeed.value * scr_frametime * vid.height / MINHEIGHT; if(scr_conlines < scr_con_current) { scr_con_current -= dt; if(scr_conlines > scr_con_current) scr_con_current = scr_conlines; } else if(scr_conlines > scr_con_current) { scr_con_current += dt; 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); else if(clearnotify++ < vid.numpages) Draw_TileClear(0, 0, vid.width, con_notifylines); else con_notifylines = 0; } static void SCR_DrawConsole(void) { if(scr_con_current) Con_DrawConsole(scr_con_current, true); else if(key_dest == key_game || key_dest == key_message) Con_DrawNotify(); // only draw notify in game clearconsole = 0; } void SCR_BeginLoadingPlaque(void) { stopallsfx(nil); 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; SCR_UpdateScreen(false); scr_drawloading = false; scr_disabled_for_loading = true; scr_disabled_time = realtime; scr_fullupdate = 0; } void SCR_EndLoadingPlaque(void) { scr_disabled_for_loading = false; scr_fullupdate = 0; Con_ClearNotify(); } static void SCR_DrawNotifyString(void) { const char *start; int l, j, 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); } /* * Displays a text string in the center of the screen and waits for a Y or N keypress. */ bool SCR_ModalMessage(const 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'; } /* 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 } static bool boundfps(void) { static double oldtime; double time, fpsmax = v_maxfps.value; if(fpsmax < 1 || fpsmax > 999) return false; time = dtime(); if(time - oldtime < 1.0 / fpsmax) return true; oldtime = time; return false; } /* * This is called every frame, and can also be called explicitly to flush * text to the screen. */ void SCR_UpdateScreen(bool drawdialog) { double t; if(scr_disabled_for_loading) {