]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_screen.c
Configure all of the CL_MeshEntities* meshes the same, the material flags decide...
[xonotic/darkplaces.git] / cl_screen.c
index fd73d8d566a4e4b3c279d608108e278bd5543152..0ef93047a3f4247388044dae298cd8d14032ed4a 100644 (file)
@@ -7,8 +7,10 @@
 #include "cl_collision.h"
 #include "libcurl.h"
 #include "csprogs.h"
+#ifdef CONFIG_VIDEO_CAPTURE
 #include "cap_avi.h"
 #include "cap_ogg.h"
+#endif
 
 // we have to include snd_main.h here only to get access to snd_renderbuffer->format.speed when writing the AVI headers
 #include "snd_main.h"
@@ -27,7 +29,9 @@ cvar_t scr_conscroll2_x = {CVAR_SAVE, "scr_conscroll2_x", "0", "scroll speed of
 cvar_t scr_conscroll2_y = {CVAR_SAVE, "scr_conscroll2_y", "0", "scroll speed of gfx/conback2 in y direction"};
 cvar_t scr_conscroll3_x = {CVAR_SAVE, "scr_conscroll3_x", "0", "scroll speed of gfx/conback3 in x direction"};
 cvar_t scr_conscroll3_y = {CVAR_SAVE, "scr_conscroll3_y", "0", "scroll speed of gfx/conback3 in y direction"};
+#ifdef CONFIG_MENU
 cvar_t scr_menuforcewhiledisconnected = {0, "scr_menuforcewhiledisconnected", "0", "forces menu while disconnected"};
+#endif
 cvar_t scr_centertime = {0, "scr_centertime","2", "how long centerprint messages show"};
 cvar_t scr_showram = {CVAR_SAVE, "showram","1", "show ram icon if low on surface cache memory (not used)"};
 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0", "show turtle icon when framerate is too low"};
@@ -52,10 +56,10 @@ cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg i
 cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"};
 cvar_t scr_screenshot_png = {CVAR_SAVE, "scr_screenshot_png","0", "save png instead of targa"};
 cvar_t scr_screenshot_gammaboost = {CVAR_SAVE, "scr_screenshot_gammaboost","1", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"};
-cvar_t scr_screenshot_hwgamma = {CVAR_SAVE, "scr_screenshot_hwgamma","1", "apply the video gamma ramp to saved screenshots and videos"};
-cvar_t scr_screenshot_alpha = {CVAR_SAVE, "scr_screenshot_alpha","0", "try to write an alpha channel to screenshots (debugging feature)"};
+cvar_t scr_screenshot_alpha = {0, "scr_screenshot_alpha","0", "try to write an alpha channel to screenshots (debugging feature)"};
 cvar_t scr_screenshot_timestamp = {CVAR_SAVE, "scr_screenshot_timestamp", "1", "use a timestamp based number of the type YYYYMMDDHHMMSSsss instead of sequential numbering"};
 // scr_screenshot_name is defined in fs.c
+#ifdef CONFIG_VIDEO_CAPTURE
 cvar_t cl_capturevideo = {0, "cl_capturevideo", "0", "enables saving of video to a .avi file using uncompressed I420 colorspace and PCM audio, note that scr_screenshot_gammaboost affects the brightness of the output)"};
 cvar_t cl_capturevideo_demo_stop = {CVAR_SAVE, "cl_capturevideo_demo_stop", "1", "automatically stops video recording when demo ends"};
 cvar_t cl_capturevideo_printfps = {CVAR_SAVE, "cl_capturevideo_printfps", "1", "prints the frames per second captured in capturevideo (is only written to the log file, not to the console, as that would be visible on the video)"};
@@ -67,6 +71,7 @@ cvar_t cl_capturevideo_nameformat = {CVAR_SAVE, "cl_capturevideo_nameformat", "d
 cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"};
 cvar_t cl_capturevideo_ogg = {CVAR_SAVE, "cl_capturevideo_ogg", "1", "save captured video data as Ogg/Vorbis/Theora streams"};
 cvar_t cl_capturevideo_framestep = {CVAR_SAVE, "cl_capturevideo_framestep", "1", "when set to n >= 1, render n frames to capture one (useful for motion blur like effects)"};
+#endif
 cvar_t r_letterbox = {0, "r_letterbox", "0", "reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)"};
 cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation distance of eyes in the world (negative values are only useful for cross-eyed viewing)"};
 cvar_t r_stereo_sidebyside = {0, "r_stereo_sidebyside", "0", "side by side views for those who can't afford glasses but can afford eye strain (note: use a negative r_stereo_separation if you want cross-eyed viewing)"};
@@ -82,7 +87,7 @@ cvar_t scr_screenshot_name_in_mapdir = {CVAR_SAVE, "scr_screenshot_name_in_mapdi
 cvar_t shownetgraph = {CVAR_SAVE, "shownetgraph", "0", "shows a graph of packet sizes and other information, 0 = off, 1 = show client netgraph, 2 = show client and server netgraphs (when hosting a server)"};
 cvar_t cl_demo_mousegrab = {0, "cl_demo_mousegrab", "0", "Allows reading the mouse input while playing demos. Useful for camera mods developed in csqc. (0: never, 1: always)"};
 cvar_t timedemo_screenshotframelist = {0, "timedemo_screenshotframelist", "", "when performing a timedemo, take screenshots of each frame in this space-separated list - example: 1 201 401"};
-cvar_t vid_touchscreen_outlinealpha = {0, "vid_touchscreen_outlinealpha", "0.25", "opacity of touchscreen area outlines"};
+cvar_t vid_touchscreen_outlinealpha = {0, "vid_touchscreen_outlinealpha", "0", "opacity of touchscreen area outlines"};
 cvar_t vid_touchscreen_overlayalpha = {0, "vid_touchscreen_overlayalpha", "0.25", "opacity of touchscreen area icons"};
 cvar_t r_speeds_graph = {CVAR_SAVE, "r_speeds_graph", "0", "display a graph of renderer statistics "};
 cvar_t r_speeds_graph_filter[8] =
@@ -102,13 +107,14 @@ cvar_t r_speeds_graph_x = {CVAR_SAVE, "r_speeds_graph_x", "0", "position of grap
 cvar_t r_speeds_graph_y = {CVAR_SAVE, "r_speeds_graph_y", "0", "position of graph"};
 cvar_t r_speeds_graph_width = {CVAR_SAVE, "r_speeds_graph_width", "256", "size of graph"};
 cvar_t r_speeds_graph_height = {CVAR_SAVE, "r_speeds_graph_height", "128", "size of graph"};
+cvar_t r_speeds_graph_maxtimedelta = {CVAR_SAVE, "r_speeds_graph_maxtimedelta", "16667", "maximum timedelta to display in the graph (this value will be the top line)"};
+cvar_t r_speeds_graph_maxdefault = {CVAR_SAVE, "r_speeds_graph_maxdefault", "100", "if the minimum and maximum observed values are closer than this, use this value as the graph range (keeps small numbers from being big graphs)"};
 
 
 
 extern cvar_t v_glslgamma;
 extern cvar_t sbar_info_pos;
 extern cvar_t r_fog_clear;
-#define WANT_SCREENSHOT_HWGAMMA (scr_screenshot_hwgamma.integer && vid_usinghwgamma)
 
 int jpeg_supported = false;
 
@@ -244,16 +250,16 @@ static void SCR_CheckDrawCenterString (void)
        SCR_DrawCenterString ();
 }
 
-static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth, int graphheight, float graphscale, const char *label, float textsize, int packetcounter, netgraphitem_t *netgraph)
+static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth, int graphheight, float graphscale, int graphlimit, const char *label, float textsize, int packetcounter, netgraphitem_t *netgraph)
 {
        netgraphitem_t *graph;
        int j, x, y, numlines;
        int totalbytes = 0;
        char bytesstring[128];
-       float g[NETGRAPH_PACKETS][6];
+       float g[NETGRAPH_PACKETS][7];
        float *a;
        float *b;
-       r_vertexgeneric_t vertex[(NETGRAPH_PACKETS+2)*5*2];
+       r_vertexgeneric_t vertex[(NETGRAPH_PACKETS+2)*6*2];
        r_vertexgeneric_t *v;
        DrawQ_Fill(graphx, graphy, graphwidth, graphheight + textsize * 2, 0, 0, 0, 0.5, 0);
        // draw the bar graph itself
@@ -267,12 +273,16 @@ static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth,
                g[j][3] = 1.0f;
                g[j][4] = 1.0f;
                g[j][5] = 1.0f;
+               g[j][6] = 1.0f;
                if (graph->unreliablebytes == NETGRAPH_LOSTPACKET)
                        g[j][1] = 0.00f;
                else if (graph->unreliablebytes == NETGRAPH_CHOKEDPACKET)
-                       g[j][2] = 0.96f;
+                       g[j][2] = 0.90f;
                else
                {
+                       if(netgraph[j].time >= netgraph[(j+NETGRAPH_PACKETS-1)%NETGRAPH_PACKETS].time)
+                               if(graph->unreliablebytes + graph->reliablebytes + graph->ackbytes >= graphlimit * (netgraph[j].time - netgraph[(j+NETGRAPH_PACKETS-1)%NETGRAPH_PACKETS].time))
+                                       g[j][2] = 0.98f;
                        g[j][3] = 1.0f    - graph->unreliablebytes * graphscale;
                        g[j][4] = g[j][3] - graph->reliablebytes   * graphscale;
                        g[j][5] = g[j][4] - graph->ackbytes        * graphscale;
@@ -280,11 +290,14 @@ static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth,
                        if (realtime - graph->time < 1.0f)
                                totalbytes += graph->unreliablebytes + graph->reliablebytes + graph->ackbytes;
                }
+               if(graph->cleartime >= 0)
+                       g[j][6] = 0.5f + 0.5f * (2.0 / M_PI) * atan((M_PI / 2.0) * (graph->cleartime - graph->time));
                g[j][1] = bound(0.0f, g[j][1], 1.0f);
                g[j][2] = bound(0.0f, g[j][2], 1.0f);
                g[j][3] = bound(0.0f, g[j][3], 1.0f);
                g[j][4] = bound(0.0f, g[j][4], 1.0f);
                g[j][5] = bound(0.0f, g[j][5], 1.0f);
+               g[j][6] = bound(0.0f, g[j][6], 1.0f);
        }
        // render the lines for the graph
        numlines = 0;
@@ -310,7 +323,10 @@ static void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth,
                VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[3], 0.0f);Vector4Set(v->color4f, 1.0f, 0.5f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++;
                VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[3], 0.0f);Vector4Set(v->color4f, 1.0f, 0.5f, 0.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++;
 
-               numlines += 5;
+               VectorSet(v->vertex3f, graphx + graphwidth * a[0], graphy + graphheight * a[6], 0.0f);Vector4Set(v->color4f, 0.0f, 0.0f, 1.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++;
+               VectorSet(v->vertex3f, graphx + graphwidth * b[0], graphy + graphheight * b[6], 0.0f);Vector4Set(v->color4f, 0.0f, 0.0f, 1.0f, 1.0f);Vector2Set(v->texcoord2f, 0.0f, 0.0f);v++;
+
+               numlines += 6;
        }
        if (numlines > 0)
        {
@@ -331,7 +347,7 @@ SCR_DrawNetGraph
 */
 static void SCR_DrawNetGraph (void)
 {
-       int i, separator1, separator2, graphwidth, graphheight, netgraph_x, netgraph_y, textsize, index, netgraphsperrow;
+       int i, separator1, separator2, graphwidth, graphheight, netgraph_x, netgraph_y, textsize, index, netgraphsperrow, graphlimit;
        float graphscale;
        netconn_t *c;
        char vabuf[1024];
@@ -349,6 +365,7 @@ static void SCR_DrawNetGraph (void)
        graphwidth = 120;
        graphheight = 70;
        graphscale = 1.0f / 1500.0f;
+       graphlimit = cl_rate.integer;
 
        netgraphsperrow = (vid_conwidth.integer + separator2) / (graphwidth * 2 + separator1 + separator2);
        netgraphsperrow = max(netgraphsperrow, 1);
@@ -357,8 +374,8 @@ static void SCR_DrawNetGraph (void)
        netgraph_x = (vid_conwidth.integer + separator2) - (1 + (index % netgraphsperrow)) * (graphwidth * 2 + separator1 + separator2);
        netgraph_y = (vid_conheight.integer - 48 - sbar_info_pos.integer + separator2) - (1 + (index / netgraphsperrow)) * (graphheight + textsize + separator2);
        c = cls.netcon;
-       SCR_DrawNetGraph_DrawGraph(netgraph_x                          , netgraph_y, graphwidth, graphheight, graphscale, "incoming", textsize, c->incoming_packetcounter, c->incoming_netgraph);
-       SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, "outgoing", textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
+       SCR_DrawNetGraph_DrawGraph(netgraph_x                          , netgraph_y, graphwidth, graphheight, graphscale, graphlimit, "incoming", textsize, c->incoming_packetcounter, c->incoming_netgraph);
+       SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, graphlimit, "outgoing", textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
        index++;
 
        if (sv.active && shownetgraph.integer >= 2)
@@ -370,8 +387,8 @@ static void SCR_DrawNetGraph (void)
                                continue;
                        netgraph_x = (vid_conwidth.integer + separator2) - (1 + (index % netgraphsperrow)) * (graphwidth * 2 + separator1 + separator2);
                        netgraph_y = (vid_conheight.integer - 48 + separator2) - (1 + (index / netgraphsperrow)) * (graphheight + textsize + separator2);
-                       SCR_DrawNetGraph_DrawGraph(netgraph_x                          , netgraph_y, graphwidth, graphheight, graphscale, va(vabuf, sizeof(vabuf), "%s", svs.clients[i].name), textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
-                       SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, ""                           , textsize, c->incoming_packetcounter, c->incoming_netgraph);
+                       SCR_DrawNetGraph_DrawGraph(netgraph_x                          , netgraph_y, graphwidth, graphheight, graphscale, graphlimit, va(vabuf, sizeof(vabuf), "%s", svs.clients[i].name), textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
+                       SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, graphlimit, ""                           , textsize, c->incoming_packetcounter, c->incoming_netgraph);
                        index++;
                }
        }
@@ -677,10 +694,13 @@ static void SCR_SetUpToDrawConsole (void)
 {
        // lines of console to display
        float conlines;
+#ifdef CONFIG_MENU
        static int framecounter = 0;
+#endif
 
        Con_CheckResize ();
 
+#ifdef CONFIG_MENU
        if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected)
        {
                if (framecounter >= 2)
@@ -690,6 +710,7 @@ static void SCR_SetUpToDrawConsole (void)
        }
        else
                framecounter = 0;
+#endif
 
        if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS)
                key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
@@ -931,7 +952,8 @@ void R_TimeReport(const char *desc)
        t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
 
        length = dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %s", t, desc);
-       length = min(length, (int)sizeof(tempbuf) - 1);
+       if (length < 0)
+               length = (int)sizeof(tempbuf) - 1;
        if (r_speeds_longestitem < length)
                r_speeds_longestitem = length;
        for (;length < r_speeds_longestitem;length++)
@@ -977,7 +999,7 @@ extern cvar_t r_viewscale;
 extern float viewscalefpsadjusted;
 static void R_TimeReport_EndFrame(void)
 {
-       int i, j, lines, y;
+       int j, lines;
        cl_locnode_t *loc;
        char string[1024+4096];
        mleaf_t *viewleaf;
@@ -1041,6 +1063,7 @@ static void R_TimeReport_EndFrame(void)
 
        if (string[0])
        {
+               int i, y;
                if (string[strlen(string)-1] == '\n')
                        string[strlen(string)-1] = 0;
                lines = 1;
@@ -1072,12 +1095,13 @@ static void R_TimeReport_EndFrame(void)
        if (r_speeds_graph.integer)
        {
                // if we currently have no graph data, reset the graph data entirely
+               int i;
                if (!cls.r_speeds_graph_data)
                        for (i = 0;i < r_stat_count;i++)
-                               cls.r_speeds_graph_datamin[i] = cls.r_speeds_graph_datamax[i] = r_refdef.stats[i];
+                               cls.r_speeds_graph_datamin[i] = cls.r_speeds_graph_datamax[i] = 0;
                if (cls.r_speeds_graph_length != r_speeds_graph_length.integer)
                {
-                       int i, stat, index, d, graph_length, *graph_data;
+                       int stat, index, d, graph_length, *graph_data;
                        cls.r_speeds_graph_length = r_speeds_graph_length.integer;
                        cls.r_speeds_graph_current = 0;
                        if (cls.r_speeds_graph_data)
@@ -1112,9 +1136,10 @@ static void R_TimeReport_EndFrame(void)
        {
                char legend[128];
                r_vertexgeneric_t *v;
-               int numlines;
+               int i, numlines;
                const int *data;
                float x, y, width, height, scalex, scaley;
+               int range_default = max(r_speeds_graph_maxdefault.integer, 1);
                int color, stat, stats, index, range_min, range_max;
                int graph_current, graph_length, *graph_data;
                int statindex[R_SPEEDS_GRAPH_COLORS];
@@ -1203,13 +1228,11 @@ static void R_TimeReport_EndFrame(void)
                                        continue;
                                // prefer to graph stats with 0 base, but if they are
                                // negative we have no choice
-                               range_min = min(cls.r_speeds_graph_datamin[stat], 0);
-                               range_max = cls.r_speeds_graph_datamax[stat];
+                               range_min = cls.r_speeds_graph_datamin[stat];
+                               range_max = max(cls.r_speeds_graph_datamax[stat], range_min + range_default);
                                // some stats we specifically override the graph scale on
                                if (stat == r_stat_timedelta)
-                                       range_max = 100000;
-                               if (range_max == range_min)
-                                       range_max++;
+                                       range_max = r_speeds_graph_maxtimedelta.integer;
                                scaley = height / (range_max - range_min);
                                // generate lines (2 vertices each)
                                // to deal with incomplete data we walk right to left
@@ -1285,10 +1308,14 @@ static void SCR_SizeDown_f (void)
        Cvar_SetValue ("viewsize",scr_viewsize.value-10);
 }
 
+#ifdef CONFIG_VIDEO_CAPTURE
 void SCR_CaptureVideo_EndVideo(void);
+#endif
 void CL_Screen_Shutdown(void)
 {
+#ifdef CONFIG_VIDEO_CAPTURE
        SCR_CaptureVideo_EndVideo();
+#endif
 }
 
 void CL_Screen_Init(void)
@@ -1308,7 +1335,9 @@ void CL_Screen_Init(void)
        Cvar_RegisterVariable (&scr_conscroll3_y);
        Cvar_RegisterVariable (&scr_conbrightness);
        Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
+#ifdef CONFIG_MENU
        Cvar_RegisterVariable (&scr_menuforcewhiledisconnected);
+#endif
        Cvar_RegisterVariable (&scr_loadingscreen_background);
        Cvar_RegisterVariable (&scr_loadingscreen_scale);
        Cvar_RegisterVariable (&scr_loadingscreen_scale_base);
@@ -1333,10 +1362,10 @@ void CL_Screen_Init(void)
        Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
        Cvar_RegisterVariable (&scr_screenshot_png);
        Cvar_RegisterVariable (&scr_screenshot_gammaboost);
-       Cvar_RegisterVariable (&scr_screenshot_hwgamma);
        Cvar_RegisterVariable (&scr_screenshot_name_in_mapdir);
        Cvar_RegisterVariable (&scr_screenshot_alpha);
        Cvar_RegisterVariable (&scr_screenshot_timestamp);
+#ifdef CONFIG_VIDEO_CAPTURE
        Cvar_RegisterVariable (&cl_capturevideo);
        Cvar_RegisterVariable (&cl_capturevideo_demo_stop);
        Cvar_RegisterVariable (&cl_capturevideo_printfps);
@@ -1348,6 +1377,7 @@ void CL_Screen_Init(void)
        Cvar_RegisterVariable (&cl_capturevideo_number);
        Cvar_RegisterVariable (&cl_capturevideo_ogg);
        Cvar_RegisterVariable (&cl_capturevideo_framestep);
+#endif
        Cvar_RegisterVariable (&r_letterbox);
        Cvar_RegisterVariable(&r_stereo_separation);
        Cvar_RegisterVariable(&r_stereo_sidebyside);
@@ -1373,6 +1403,8 @@ void CL_Screen_Init(void)
        Cvar_RegisterVariable(&r_speeds_graph_y);
        Cvar_RegisterVariable(&r_speeds_graph_width);
        Cvar_RegisterVariable(&r_speeds_graph_height);
+       Cvar_RegisterVariable(&r_speeds_graph_maxtimedelta);
+       Cvar_RegisterVariable(&r_speeds_graph_maxdefault);
 
        // if we want no console, turn it off here too
        if (COM_CheckParm ("-noconsole"))
@@ -1384,7 +1416,9 @@ void CL_Screen_Init(void)
        Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
        Cmd_AddCommand ("infobar", SCR_InfoBar_f, "display a text in the infobar (usage: infobar expiretime string)");
 
+#ifdef CONFIG_VIDEO_CAPTURE
        SCR_CaptureVideo_Ogg_Init();
+#endif
 
        scr_initialized = true;
 }
@@ -1512,6 +1546,7 @@ void SCR_ScreenShot_f (void)
        Mem_Free (buffer2);
 }
 
+#ifdef CONFIG_VIDEO_CAPTURE
 static void SCR_CaptureVideo_BeginVideo(void)
 {
        double r, g, b;
@@ -1573,17 +1608,10 @@ Cb = R * -.169 + G * -.332 + B *  .500 + 128.;
 Cr = R *  .500 + G * -.419 + B * -.0813 + 128.;
 */
 
-       if(WANT_SCREENSHOT_HWGAMMA)
-       {
-               VID_BuildGammaTables(&cls.capturevideo.vidramp[0], 256);
-       }
-       else
-       {
-               // identity gamma table
-               BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp, 256);
-               BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256, 256);
-               BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256*2, 256);
-       }
+       // identity gamma table
+       BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp, 256);
+       BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256, 256);
+       BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256*2, 256);
        if(scr_screenshot_gammaboost.value != 1)
        {
                double igamma = 1 / scr_screenshot_gammaboost.value;
@@ -1741,7 +1769,7 @@ static void SCR_CaptureVideo_VideoFrame(int newframestepframenum)
 
 void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length)
 {
-       cls.capturevideo.soundsampleframe += length;
+       cls.capturevideo.soundsampleframe += (int)length;
        cls.capturevideo.soundframe(paintbuffer, length);
 }
 
@@ -1788,6 +1816,7 @@ static void SCR_CaptureVideo(void)
        else if (cls.capturevideo.active)
                SCR_CaptureVideo_EndVideo();
 }
+#endif
 
 /*
 ===============
@@ -1921,10 +1950,12 @@ void SHOWLMP_decodeshow(void)
                showlmp_t *oldshowlmps = cl.showlmps;
                cl.max_showlmps += 16;
                cl.showlmps = (showlmp_t *) Mem_Alloc(cls.levelmempool, cl.max_showlmps * sizeof(showlmp_t));
-               if (cl.num_showlmps)
-                       memcpy(cl.showlmps, oldshowlmps, cl.num_showlmps * sizeof(showlmp_t));
                if (oldshowlmps)
+               {
+                       if (cl.num_showlmps)
+                               memcpy(cl.showlmps, oldshowlmps, cl.num_showlmps * sizeof(showlmp_t));
                        Mem_Free(oldshowlmps);
+               }
        }
        for (k = 0;k < cl.max_showlmps;k++)
                if (cl.showlmps[k].isactive && !strcmp(cl.showlmps[k].label, lmplabel))
@@ -1966,22 +1997,15 @@ qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *b
 
        GL_ReadPixelsBGRA(x, y, width, height, buffer1);
 
-       if(gammacorrect && (scr_screenshot_gammaboost.value != 1 || WANT_SCREENSHOT_HWGAMMA))
+       if(gammacorrect && (scr_screenshot_gammaboost.value != 1))
        {
                int i;
                double igamma = 1.0 / scr_screenshot_gammaboost.value;
                unsigned short vidramp[256 * 3];
-               if(WANT_SCREENSHOT_HWGAMMA)
-               {
-                       VID_BuildGammaTables(&vidramp[0], 256);
-               }
-               else
-               {
-                       // identity gamma table
-                       BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp, 256);
-                       BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256, 256);
-                       BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256*2, 256);
-               }
+               // identity gamma table
+               BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp, 256);
+               BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256, 256);
+               BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256*2, 256);
                if(scr_screenshot_gammaboost.value != 1)
                {
                        for (i = 0;i < 256 * 3;i++)
@@ -2028,7 +2052,7 @@ qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *b
 //=============================================================================
 
 int scr_numtouchscreenareas;
-scr_touchscreenarea_t scr_touchscreenareas[16];
+scr_touchscreenarea_t scr_touchscreenareas[128];
 
 static void SCR_DrawTouchscreenOverlay(void)
 {
@@ -2049,14 +2073,23 @@ static void SCR_DrawTouchscreenOverlay(void)
                pic = a->pic ? Draw_CachePic(a->pic) : NULL;
                if (pic && pic->tex != r_texture_notexture)
                        DrawQ_Pic(a->rect[0], a->rect[1], Draw_CachePic(a->pic), a->rect[2], a->rect[3], 1, 1, 1, vid_touchscreen_overlayalpha.value * (0.5f + 0.5f * a->active), 0);
+               if (a->text && a->text[0])
+               {
+                       int textwidth = DrawQ_TextWidth(a->text, 0, a->textheight, a->textheight, false, FONT_CHAT);
+                       DrawQ_String(a->rect[0] + (a->rect[2] - textwidth) * 0.5f, a->rect[1] + (a->rect[3] - a->textheight) * 0.5f, a->text, 0, a->textheight, a->textheight, 1.0f, 1.0f, 1.0f, vid_touchscreen_overlayalpha.value, 0, NULL, false, FONT_CHAT);
+               }
        }
 }
 
 void R_ClearScreen(qboolean fogcolor)
 {
        float clearcolor[4];
-       // clear to black
-       Vector4Clear(clearcolor);
+       if (scr_screenshot_alpha.integer)
+               // clear to transparency (so png screenshots can contain alpha channel, useful for building model pictures)
+               Vector4Set(clearcolor, 0.0f, 0.0f, 0.0f, 0.0f);
+       else
+               // clear to opaque black (if we're being composited it might otherwise render as transparent)
+               Vector4Set(clearcolor, 0.0f, 0.0f, 0.0f, 1.0f);
        if (fogcolor && r_fog_clear.integer)
        {
                R_UpdateFog();
@@ -2149,8 +2182,12 @@ static void SCR_DrawScreen (void)
                r_refdef.view.ortho_x = atan(r_refdef.view.frustum_x) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView
                r_refdef.view.ortho_y = atan(r_refdef.view.frustum_y) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView
 
-               if(!CL_VM_UpdateView())
-                       R_RenderView();
+               // if CSQC is loaded, it is required to provide the CSQC_UpdateView function,
+               // and won't render a view if it does not call that.
+               if (cl.csqc_loaded)
+                       CL_VM_UpdateView(r_stereo_side ? 0.0 : max(0.0, cl.time - cl.oldtime));
+               else
+                       R_RenderView(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
        }
 
        if (!r_stereo_sidebyside.integer && !r_stereo_horizontal.integer && !r_stereo_vertical.integer)
@@ -2212,7 +2249,9 @@ static void SCR_DrawScreen (void)
                SCR_CheckDrawCenterString();
        }
        SCR_DrawNetGraph ();
+#ifdef CONFIG_MENU
        MR_Draw();
+#endif
        CL_DrawVideo();
        R_Shadow_EditLights_DrawSelectedLightProperties();
 
@@ -2728,7 +2767,7 @@ void CL_UpdateScreen(void)
 
        loadingscreendone = false;
 
-       if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
+       if(IS_NEXUIZ_DERIVED(gamemode))
        {
                // play a bit with the palette (experimental)
                palette_rgb_pantscolormap[15][0] = (unsigned char) (128 + 127 * sin(cl.time / exp(1.0f) + 0.0f*M_PI/3.0f));
@@ -2882,12 +2921,18 @@ void CL_UpdateScreen(void)
                        qglDrawBuffer(GL_BACK_LEFT);
 
                SCR_DrawScreen();
+               r_stereo_side = 0;
        }
        else
 #endif
+       {
+               r_stereo_side = 0;
                SCR_DrawScreen();
+       }
 
+#ifdef CONFIG_VIDEO_CAPTURE
        SCR_CaptureVideo();
+#endif
 
        if (qglFlush)
                qglFlush(); // FIXME: should we really be using qglFlush here?