]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_screen.c
added viewzoom extension to QC and client (smooth sniper zooming, with sensitivity...
[xonotic/darkplaces.git] / cl_screen.c
index 0d6ba443c6e847178cfad605424b91ab606b7d47..8f2f269d9c919c887ddccd50eccffe5f136c756c 100644 (file)
 
 #include "quakedef.h"
 
+cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100"};
+cvar_t scr_fov = {CVAR_SAVE, "fov","90"};      // 10 - 170
+cvar_t scr_conspeed = {CVAR_SAVE, "scr_conspeed","900"}; // LordHavoc: quake used 300
+cvar_t scr_centertime = {0, "scr_centertime","2"};
+cvar_t scr_showram = {CVAR_SAVE, "showram","1"};
+cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0"};
+cvar_t scr_showpause = {CVAR_SAVE, "showpause","1"};
+cvar_t scr_printspeed = {0, "scr_printspeed","8"};
+cvar_t scr_2dresolution = {CVAR_SAVE, "scr_2dresolution", "1"};
+
+qboolean       scr_initialized;                // ready to draw
+
+float          scr_con_current;
+float          scr_conlines;           // lines of console to display
+
+int                    clearconsole;
+int                    clearnotify;
+
+qboolean       scr_disabled_for_loading;
+//qboolean     scr_drawloading;
+//float                scr_disabled_time;
+
 static byte menuplyr_pixels[4096];
 
+/*
+===============================================================================
+
+CENTER PRINTING
+
+===============================================================================
+*/
+
+char           scr_centerstring[1024];
+float          scr_centertime_start;   // for slow victory printing
+float          scr_centertime_off;
+int                    scr_center_lines;
+int                    scr_erase_lines;
+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++;
+       }
+}
+
+
+void SCR_DrawCenterString (void)
+{
+       char    *start;
+       int             l;
+       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 = 9999;
+
+       scr_erase_center = 0;
+       start = scr_centerstring;
+
+       if (scr_center_lines <= 4)
+               y = vid.conheight*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.conwidth - l*8)/2;
+               if (l > 0)
+               {
+                       if (remaining < l)
+                               l = remaining;
+                       DrawQ_String(x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
+                       remaining -= l;
+                       if (remaining <= 0)
+                               return;
+               }
+
+               y += 8;
+
+               while (*start && *start != '\n')
+                       start++;
+
+               if (!*start)
+                       break;
+               start++;                // skip the \n
+       } while (1);
+}
+
+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 ();
+}
+
+/*
+==============
+SCR_DrawRam
+==============
+*/
+void SCR_DrawRam (void)
+{
+//     if (!scr_showram.integer)
+//             return;
+//     DrawQ_Pic (32, 0, "ram", 0, 0, 1, 1, 1, 1, 0);
+}
+
+/*
+==============
+SCR_DrawTurtle
+==============
+*/
+void SCR_DrawTurtle (void)
+{
+       static int      count;
+
+       if (cls.state != ca_connected)
+               return;
+
+       if (!scr_showturtle.integer)
+               return;
+
+       if (host_frametime < 0.1)
+       {
+               count = 0;
+               return;
+       }
+
+       count++;
+       if (count < 3)
+               return;
+
+       DrawQ_Pic (0, 0, "turtle", 0, 0, 1, 1, 1, 1, 0);
+}
+
+/*
+==============
+SCR_DrawNet
+==============
+*/
+void SCR_DrawNet (void)
+{
+       if (cls.state != ca_connected)
+               return;
+       if (realtime - cl.last_received_message < 0.3)
+               return;
+       if (cls.demoplayback)
+               return;
+
+       DrawQ_Pic (64, 0, "net", 0, 0, 1, 1, 1, 1, 0);
+}
+
+/*
+==============
+DrawPause
+==============
+*/
+void SCR_DrawPause (void)
+{
+       cachepic_t      *pic;
+
+       if (cls.state != ca_connected)
+               return;
+
+       if (!scr_showpause.integer)             // turn off for screenshots
+               return;
+
+       if (!cl.paused)
+               return;
+
+       pic = Draw_CachePic ("gfx/pause.lmp");
+       DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/pause.lmp", 0, 0, 1, 1, 1, 1, 0);
+}
+
+
+
+/*
+==============
+SCR_DrawLoading
+==============
+*/
+/*
+void SCR_DrawLoading (void)
+{
+       cachepic_t      *pic;
+
+       if (!scr_drawloading)
+               return;
+
+       pic = Draw_CachePic ("gfx/loading.lmp");
+       DrawQ_Pic ((vid.conwidth - pic->width)/2, (vid.conheight - pic->height)/2, "gfx/loading.lmp", 0, 0, 1, 1, 1, 1, 0);
+}
+*/
+
+
+
+//=============================================================================
+
+
+/*
+==================
+SCR_SetUpToDrawConsole
+==================
+*/
+void SCR_SetUpToDrawConsole (void)
+{
+       Con_CheckResize ();
+
+// decide on the height of the console
+       con_forcedup = !cl.worldmodel || cls.signon != SIGNONS;
+
+       if (con_forcedup)
+       {
+               scr_conlines = vid.conheight;           // full screen
+               scr_con_current = scr_conlines;
+       }
+       else if (key_dest == key_console)
+               scr_conlines = vid.conheight/2; // half screen
+       else
+               scr_conlines = 0;                               // none visible
+
+       if (scr_conlines < scr_con_current)
+       {
+               scr_con_current -= scr_conspeed.value*host_realframetime;
+               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_realframetime;
+               if (scr_conlines < scr_con_current)
+                       scr_con_current = scr_conlines;
+       }
+}
+
+/*
+==================
+SCR_DrawConsole
+==================
+*/
+void SCR_DrawConsole (void)
+{
+       if (scr_con_current)
+       {
+               Con_DrawConsole (scr_con_current);
+               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)
+{
+       S_StopAllSounds (true);
+
+//     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_UpdateScreen ();
+
+//     scr_disabled_for_loading = true;
+//     scr_disabled_time = realtime;
+}
+*/
+
+/*
+===============
+SCR_EndLoadingPlaque
+
+================
+*/
+/*
+void SCR_EndLoadingPlaque (void)
+{
+//     scr_disabled_for_loading = false;
+       scr_drawloading = false;
+       Con_ClearNotify ();
+}
+*/
+
+//=============================================================================
+
+char   *scr_notifystring;
+
+void SCR_DrawNotifyString (void)
+{
+       char    *start;
+       int             l;
+       int             x, y;
+
+       start = scr_notifystring;
+
+       y = vid.conheight*0.35;
+
+       do
+       {
+       // scan the width of the line
+               for (l=0 ; l<40 ; l++)
+                       if (start[l] == '\n' || !start[l])
+                               break;
+               x = (vid.conwidth - l*8)/2;
+               DrawQ_String (x, y, start, l, 8, 8, 1, 1, 1, 1, 0);
+
+               y += 8;
+
+               while (*start && *start != '\n')
+                       start++;
+
+               if (!*start)
+                       break;
+               start++;                // skip the \n
+       }
+       while (1);
+}
+
+void DrawCrosshair(int num);
+
+char r_speeds_string[1024];
+int speedstringcount, r_timereport_active;
+double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
+
+void R_TimeReport(char *desc)
+{
+       char tempbuf[256];
+       int length;
+       int t;
+
+       if (!r_timereport_active)
+               return;
+
+       r_timereport_temp = r_timereport_current;
+       r_timereport_current = Sys_DoubleTime();
+       t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0);
+
+       sprintf(tempbuf, "%8i %s", t, desc);
+       length = strlen(tempbuf);
+       while (length < 20)
+               tempbuf[length++] = ' ';
+       tempbuf[length] = 0;
+       if (speedstringcount + length > (vid.conwidth / 8))
+       {
+               strcat(r_speeds_string, "\n");
+               speedstringcount = 0;
+       }
+       // skip the space at the beginning if it's the first on the line
+       if (speedstringcount == 0)
+       {
+               strcat(r_speeds_string, tempbuf + 1);
+               speedstringcount = length - 1;
+       }
+       else
+       {
+               strcat(r_speeds_string, tempbuf);
+               speedstringcount += length;
+       }
+}
+
+void R_TimeReport_Start(void)
+{
+       r_timereport_active = r_speeds.integer && cl.worldmodel && cls.state == ca_connected;
+       r_speeds_string[0] = 0;
+       if (r_timereport_active)
+       {
+               speedstringcount = 0;
+               AngleVectors (r_refdef.viewangles, vpn, NULL, NULL);
+               //sprintf(r_speeds_string, "org:'%c%6.2f %c%6.2f %c%6.2f' ang:'%c%3.0f %c%3.0f %c%3.0f' dir:'%c%2.3f %c%2.3f %c%2.3f'\n%6i walls %6i dlitwalls %7i modeltris %7i meshtris\nBSP: %6i faces %6i nodes %6i leafs\n%4i models %4i bmodels %4i sprites %5i particles %3i dlights\n",
+               //      r_refdef.vieworg[0] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[0]), r_refdef.vieworg[1] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[1]), r_refdef.vieworg[2] < 0 ? '-' : ' ', fabs(r_refdef.vieworg[2]),
+               //      r_refdef.viewangles[0] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[0]), r_refdef.viewangles[1] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[1]), r_refdef.viewangles[2] < 0 ? '-' : ' ', fabs(r_refdef.viewangles[2]),
+               //      vpn[0] < 0 ? '-' : ' ', fabs(vpn[0]), vpn[1] < 0 ? '-' : ' ', fabs(vpn[1]), vpn[2] < 0 ? '-' : ' ', fabs(vpn[2]),
+               sprintf(r_speeds_string,
+                       "org:'%+8.2f %+8.2f %+8.2f' ang:'%+4.0f %+4.0f %+4.0f' dir:'%+2.3f %+2.3f %+2.3f'\n"
+                       "world:%6i faces%6i nodes%6i leafs%6i walls%6i dlitwalls\n"
+                       "%5i models%5i bmodels%5i sprites%6i particles%4i dlights\n"
+                       "%6i modeltris%6i transmeshs%6i transtris%6i meshs%6i meshtris\n",
+                       r_refdef.vieworg[0], r_refdef.vieworg[1], r_refdef.vieworg[2], r_refdef.viewangles[0], r_refdef.viewangles[1], r_refdef.viewangles[2], vpn[0], vpn[1], vpn[2],
+                       c_faces, c_nodes, c_leafs, c_brush_polys, c_light_polys,
+                       c_models, c_bmodels, c_sprites, c_particles, c_dlights,
+                       c_alias_polys, c_transmeshs, c_transtris, c_meshs, c_meshtris);
+
+               c_brush_polys = 0;
+               c_alias_polys = 0;
+               c_light_polys = 0;
+               c_faces = 0;
+               c_nodes = 0;
+               c_leafs = 0;
+               c_models = 0;
+               c_bmodels = 0;
+               c_sprites = 0;
+               c_particles = 0;
+       //      c_dlights = 0;
+
+               r_timereport_start = Sys_DoubleTime();
+       }
+}
+
+void R_TimeReport_End(void)
+{
+       r_timereport_current = r_timereport_start;
+       R_TimeReport("total");
+
+       if (r_timereport_active)
+       {
+               int i, j, lines, y;
+               lines = 1;
+               for (i = 0;r_speeds_string[i];i++)
+                       if (r_speeds_string[i] == '\n')
+                               lines++;
+               y = vid.conheight - sb_lines - lines * 8/* - 8*/;
+               i = j = 0;
+               DrawQ_Fill(0, y, vid.conwidth, lines * 8, 0, 0, 0, 0.5, 0);
+               while (r_speeds_string[i])
+               {
+                       j = i;
+                       while (r_speeds_string[i] && r_speeds_string[i] != '\n')
+                               i++;
+                       if (i - j > 0)
+                               DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
+                       if (r_speeds_string[i] == '\n')
+                               i++;
+                       y += 8;
+               }
+       }
+}
+
+/*
+=================
+SCR_SizeUp_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeUp_f (void)
+{
+       Cvar_SetValue ("viewsize",scr_viewsize.value+10);
+}
+
+
+/*
+=================
+SCR_SizeDown_f
+
+Keybinding command
+=================
+*/
+void SCR_SizeDown_f (void)
+{
+       Cvar_SetValue ("viewsize",scr_viewsize.value-10);
+}
+
 void CL_Screen_Init(void)
 {
        qpic_t *dat;
 
+       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_2dresolution);
+
+       Cmd_AddCommand ("sizeup",SCR_SizeUp_f);
+       Cmd_AddCommand ("sizedown",SCR_SizeDown_f);
+
+       scr_initialized = true;
+
        // HACK HACK HACK
        // load the image data for the player image in the config menu
        dat = (qpic_t *)COM_LoadFile ("gfx/menuplyr.lmp", false);
@@ -146,24 +660,101 @@ void DrawQ_PicTranslate (int x, int y, char *picname, byte *translation)
        DrawQ_Pic(x, y, picname, 0, 0, 1, 1, 1, 1, 0);
 }
 
-void V_CalcRefdef (void);
-void CL_UpdateScreen(void)
+
+/*
+====================
+CalcFov
+====================
+*/
+float CalcFov (float fov_x, float width, float height)
 {
-       DrawQ_Clear();
+       // calculate vision size and alter by aspect, then convert back to angle
+       return atan (height / (width / tan(fov_x/360*M_PI))) * 360 / M_PI;
+}
 
-       SHOWLMP_drawall();
+/*
+=================
+SCR_CalcRefdef
 
-       V_UpdateBlends();
-       V_CalcRefdef ();
+Must be called whenever vid changes
+Internal use only
+=================
+*/
+static void SCR_CalcRefdef (void)
+{
+       float size;
+       int contents;
 
-       SCR_UpdateScreen();
-}
+//========================================
 
-void CL_Screen_NewMap(void)
-{
-       SHOWLMP_clear();
+// bound viewsize
+       if (scr_viewsize.value < 30)
+               Cvar_Set ("viewsize","30");
+       if (scr_viewsize.value > 120)
+               Cvar_Set ("viewsize","120");
+
+// bound field of view
+       if (scr_fov.value < 10)
+               Cvar_Set ("fov","10");
+       if (scr_fov.value > 170)
+               Cvar_Set ("fov","170");
+
+// intermission is always full screen
+       if (cl.intermission)
+       {
+               size = 1;
+               sb_lines = 0;
+       }
+       else
+       {
+               if (scr_viewsize.value >= 120)
+                       sb_lines = 0;           // no status bar at all
+               else if (scr_viewsize.value >= 110)
+                       sb_lines = 24;          // no inventory
+               else
+                       sb_lines = 24+16+8;
+               size = scr_viewsize.value * (1.0 / 100.0);
+       }
+
+       if (size >= 1)
+       {
+               r_refdef.width = vid.realwidth;
+               r_refdef.height = vid.realheight;
+               r_refdef.x = 0;
+               r_refdef.y = 0;
+       }
+       else
+       {
+               r_refdef.width = vid.realwidth * size;
+               r_refdef.height = vid.realheight * size;
+               r_refdef.x = (vid.realwidth - r_refdef.width)/2;
+               r_refdef.y = (vid.realheight - r_refdef.height)/2;
+       }
+
+       r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
+       r_refdef.height = bound(0, r_refdef.height, vid.realheight);
+       r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width) + vid.realx;
+       r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height) + vid.realy;
+
+       // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
+       r_refdef.fov_x = scr_fov.value * cl.viewzoom;
+       r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.width, r_refdef.height);
+
+       if (cl.worldmodel)
+       {
+               Mod_CheckLoaded(cl.worldmodel);
+               contents = Mod_PointInLeaf(r_refdef.vieworg, cl.worldmodel)->contents;
+               if (contents != CONTENTS_EMPTY && contents != CONTENTS_SOLID)
+               {
+                       r_refdef.fov_x *= (sin(cl.time * 4.7) * 0.015 + 0.985);
+                       r_refdef.fov_y *= (sin(cl.time * 3.0) * 0.015 + 0.985);
+               }
+       }
 }
 
+
+void V_CalcRefdef (void);
+
 //=============================================================================
 
 // LordHavoc: SHOWLMP stuff
@@ -247,3 +838,84 @@ void SHOWLMP_clear(void)
        for (i = 0;i < SHOWLMP_MAXLABELS;i++)
                showlmp[i].isactive = false;
 }
+
+void CL_UpdateScreen(void)
+{
+       static float old2dresolution = -1;
+
+       if (scr_disabled_for_loading)
+               return;
+
+       if (!scr_initialized || !con_initialized)
+               return;                         // not initialized yet
+
+       R_TimeReport("other");
+
+       VID_GetWindowSize (&vid.realx, &vid.realy, &vid.realwidth, &vid.realheight);
+
+       VID_UpdateGamma(false);
+
+       if (scr_2dresolution.value != old2dresolution)
+       {
+               Cvar_SetValue("scr_2dresolution", bound(0.0f, scr_2dresolution.value, 1.0f));
+               old2dresolution = scr_2dresolution.value;
+       }
+
+       if (vid.realwidth > 320)
+       {
+               vid.conwidth = (vid.realwidth - 320) * scr_2dresolution.value + 320;
+               vid.conwidth = bound(320, vid.conwidth, vid.realwidth);
+       }
+       else
+               vid.conwidth = 320;
+
+       if (vid.realheight > 240)
+       {
+               vid.conheight = (vid.realheight - 240) * scr_2dresolution.value + 240;
+               vid.conheight = bound(240, vid.conheight, vid.realheight);
+       }
+       else
+               vid.conheight = 240;
+
+       SCR_SetUpToDrawConsole();
+
+       // determine size of refresh window
+       SCR_CalcRefdef();
+
+       DrawQ_Clear();
+
+       V_UpdateBlends();
+       V_CalcRefdef ();
+
+       R_TimeReport("setup");
+
+       SCR_DrawRam();
+       SCR_DrawNet();
+       SCR_DrawTurtle();
+       SCR_DrawPause();
+       SCR_CheckDrawCenterString();
+       Sbar_Draw();
+       SHOWLMP_drawall();
+
+       SCR_DrawConsole();
+
+       ui_draw();
+
+       R_TimeReport("2d");
+
+       // add r_speeds text to queue
+       R_TimeReport_End();
+
+       // start a new timing run
+       R_TimeReport_Start();
+
+       // make menu fade everything else on the screen
+       M_Draw();
+
+       SCR_UpdateScreen();
+}
+
+void CL_Screen_NewMap(void)
+{
+       SHOWLMP_clear();
+}