]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_screen.c
fix a mistake in the recent commit
[xonotic/darkplaces.git] / cl_screen.c
index c2efe5d72467247395035af32711c3514425feab..09f56f8ac8833e47a0539d884fafdef707a0cf34 100644 (file)
@@ -50,6 +50,7 @@ cvar_t scr_stipple = {0, "scr_stipple", "0", "interlacing-like stippling of the
 cvar_t scr_refresh = {0, "scr_refresh", "1", "allows you to completely shut off rendering for benchmarking purposes"};
 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)"};
 
+#define AVI_MASTER_INDEX_SIZE 640 // GB ought to be enough for anyone
 
 int jpeg_supported = false;
 
@@ -682,7 +683,8 @@ void R_TimeReport_Frame(void)
                if (loc)
                        sprintf(r_speeds_string + strlen(r_speeds_string), "Location: %s\n", loc->name);
                sprintf(r_speeds_string + strlen(r_speeds_string), "org:'%+8.2f %+8.2f %+8.2f' dir:'%+2.3f %+2.3f %+2.3f'\n", r_view.origin[0], r_view.origin[1], r_view.origin[2], r_view.forward[0], r_view.forward[1], r_view.forward[2]);
-               sprintf(r_speeds_string + strlen(r_speeds_string), "%5i entities%6i surfaces%6i triangles%5i leafs%5i portals%6i particles\n", r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles, r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles);
+               sprintf(r_speeds_string + strlen(r_speeds_string), "%7i surfaces%7i triangles %5i entities (%7i surfaces%7i triangles)\n", r_refdef.stats.world_surfaces, r_refdef.stats.world_triangles, r_refdef.stats.entities, r_refdef.stats.entities_surfaces, r_refdef.stats.entities_triangles);
+               sprintf(r_speeds_string + strlen(r_speeds_string), "%5ileafs%5i portals%6i particles%6i decals\n", r_refdef.stats.world_leafs, r_refdef.stats.world_portals, r_refdef.stats.particles, r_refdef.stats.decals);
                sprintf(r_speeds_string + strlen(r_speeds_string), "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n", r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles);
                if (r_refdef.stats.bloom)
                        sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3, r_refdef.stats.bloom_copypixels, r_refdef.stats.bloom_drawpixels);
@@ -920,34 +922,100 @@ static void SCR_CaptureVideo_RIFF_Pop(void)
        }
 }
 
-static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunksize, int flags)
+static void GrowBuf(sizebuf_t *buf, int extralen)
 {
-       if (cls.capturevideo.riffstacklevel != 2)
-               Sys_Error("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", cls.capturevideo.riffstacklevel);
-       if (cls.capturevideo.riffindexbuffer.cursize + 16 > cls.capturevideo.riffindexbuffer.maxsize)
+       if(buf->cursize + extralen > buf->maxsize)
        {
-               int oldsize = cls.capturevideo.riffindexbuffer.maxsize;
+               int oldsize = buf->maxsize;
                unsigned char *olddata;
-               olddata = cls.capturevideo.riffindexbuffer.data;
-               cls.capturevideo.riffindexbuffer.maxsize = max(cls.capturevideo.riffindexbuffer.maxsize * 2, 4096);
-               cls.capturevideo.riffindexbuffer.data = Mem_Alloc(tempmempool, cls.capturevideo.riffindexbuffer.maxsize);
-               if (olddata)
+               olddata = buf->data;
+               buf->maxsize = max(buf->maxsize * 2, 4096);
+               buf->data = Mem_Alloc(tempmempool, buf->maxsize);
+               if(olddata)
                {
-                       memcpy(cls.capturevideo.riffindexbuffer.data, olddata, oldsize);
+                       memcpy(buf->data, olddata, oldsize);
                        Mem_Free(olddata);
                }
        }
+}
+
+static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunksize, int flags)
+{
+       if (cls.capturevideo.riffstacklevel != 2)
+               Sys_Error("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", cls.capturevideo.riffstacklevel);
+       GrowBuf(&cls.capturevideo.riffindexbuffer, 16);
+       SCR_CaptureVideo_RIFF_Flush();
        MSG_WriteUnterminatedString(&cls.capturevideo.riffindexbuffer, chunkfourcc);
        MSG_WriteLong(&cls.capturevideo.riffindexbuffer, flags);
        MSG_WriteLong(&cls.capturevideo.riffindexbuffer, (int)FS_Tell(cls.capturevideo.videofile) - cls.capturevideo.riffstackstartoffset[1]);
        MSG_WriteLong(&cls.capturevideo.riffindexbuffer, chunksize);
 }
 
+static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChunkId, fs_offset_t masteridx_counter, int *masteridx_count, fs_offset_t masteridx_start)
+{
+       int nMatching;
+       int i;
+       fs_offset_t ix = SCR_CaptureVideo_RIFF_GetPosition();
+       fs_offset_t pos;
+
+       if(*masteridx_count >= AVI_MASTER_INDEX_SIZE)
+               return;
+
+       nMatching = 0; // go through index and enumerate them
+       for(i = 0; i < cls.capturevideo.riffindexbuffer.cursize; i += 16)
+               if(!memcmp(cls.capturevideo.riffindexbuffer.data + i, dwChunkId, 4))
+                       ++nMatching;
+
+       SCR_CaptureVideo_RIFF_Push(fcc, NULL);
+       SCR_CaptureVideo_RIFF_Write16(2); // wLongsPerEntry
+       SCR_CaptureVideo_RIFF_Write16(0x0100); // bIndexType=1, bIndexSubType=0
+       SCR_CaptureVideo_RIFF_Write32(nMatching); // nEntriesInUse
+       SCR_CaptureVideo_RIFF_WriteFourCC(dwChunkId); // dwChunkId
+       SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.videofile_ix_movistart & (fs_offset_t) 0xFFFFFFFFu);
+       SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) cls.capturevideo.videofile_ix_movistart) >> 32);
+       SCR_CaptureVideo_RIFF_Write32(0); // dwReserved
+
+       for(i = 0; i < cls.capturevideo.riffindexbuffer.cursize; i += 16)
+               if(!memcmp(cls.capturevideo.riffindexbuffer.data + i, dwChunkId, 4))
+               {
+                       unsigned int *p = (unsigned int *) (cls.capturevideo.riffindexbuffer.data + i);
+                       unsigned int flags = p[1];
+                       unsigned int rpos = p[2];
+                       unsigned int size = p[3];
+                       size &= ~0x80000000;
+                       if(!(flags & 0x10)) // no keyframe?
+                               size |= 0x80000000;
+                       SCR_CaptureVideo_RIFF_Write32(rpos + 8);
+                       SCR_CaptureVideo_RIFF_Write32(size);
+               }
+
+       SCR_CaptureVideo_RIFF_Pop();
+       pos = SCR_CaptureVideo_RIFF_GetPosition();
+       SCR_CaptureVideo_RIFF_Flush();
+
+       FS_Seek(cls.capturevideo.videofile, masteridx_start + 16 * *masteridx_count, SEEK_SET);
+       SCR_CaptureVideo_RIFF_Write32(ix & (fs_offset_t) 0xFFFFFFFFu);
+       SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) ix) >> 32);
+       SCR_CaptureVideo_RIFF_Write32(pos - ix);
+       SCR_CaptureVideo_RIFF_Write32(nMatching);
+       SCR_CaptureVideo_RIFF_Flush();
+
+       FS_Seek(cls.capturevideo.videofile, masteridx_counter, SEEK_SET);
+       SCR_CaptureVideo_RIFF_Write32(++*masteridx_count);
+       SCR_CaptureVideo_RIFF_Flush();
+
+       FS_Seek(cls.capturevideo.videofile, 0, SEEK_END);
+}
+
 static void SCR_CaptureVideo_RIFF_Finish(qboolean final)
 {
        // close the "movi" list
        SCR_CaptureVideo_RIFF_Pop();
-       // write the idx1 chunk that we've been building while saving the frames
+       if(cls.capturevideo.videofile_ix_master_video_inuse_offset)
+               SCR_CaptureVideo_RIFF_MakeIxChunk("ix00", "00dc", cls.capturevideo.videofile_ix_master_video_inuse_offset, &cls.capturevideo.videofile_ix_master_video_inuse, cls.capturevideo.videofile_ix_master_video_start_offset);
+       if(cls.capturevideo.videofile_ix_master_audio_inuse_offset)
+               SCR_CaptureVideo_RIFF_MakeIxChunk("ix01", "01wb", cls.capturevideo.videofile_ix_master_audio_inuse_offset, &cls.capturevideo.videofile_ix_master_audio_inuse, cls.capturevideo.videofile_ix_master_audio_start_offset);
+       // write the idx1 chunk that we've been building while saving the frames (for old style players)
        if(final && cls.capturevideo.videofile_firstchunkframes_offset)
        // TODO replace index creating by OpenDML ix##/##ix/indx chunk so it works for more than one AVI part too
        {
@@ -985,12 +1053,13 @@ static void SCR_CaptureVideo_RIFF_OverflowCheck(int framesize)
 
        // if this would overflow the windows limit of 1GB per RIFF chunk, we need
        // to close the current RIFF chunk and open another for future frames
-       if (8 + cursize + framesize + cls.capturevideo.riffindexbuffer.cursize + 8 > 1<<30)
+       if (8 + cursize + framesize + cls.capturevideo.riffindexbuffer.cursize + 8 + cls.capturevideo.riffindexbuffer.cursize + 64 > 1<<30) // note that the Ix buffer takes less space... I just don't dare to / 2 here now... sorry, maybe later
        {
                SCR_CaptureVideo_RIFF_Finish(false);
                // begin a new 1GB extended section of the AVI
                SCR_CaptureVideo_RIFF_Push("RIFF", "AVIX");
                SCR_CaptureVideo_RIFF_Push("LIST", "movi");
+               cls.capturevideo.videofile_ix_movistart = cls.capturevideo.riffstackstartoffset[1];
        }
 }
 
@@ -1054,8 +1123,8 @@ void SCR_CaptureVideo_BeginVideo(void)
        cls.capturevideo.frame = 0;
        cls.capturevideo.soundsampleframe = 0;
        cls.capturevideo.realtime = cl_capturevideo_realtime.integer != 0;
-       cls.capturevideo.screenbuffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
-       cls.capturevideo.outbuffer = (unsigned char *)Mem_Alloc(tempmempool, width * height * (3+3+3) + 18);
+       cls.capturevideo.screenbuffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4);
+       cls.capturevideo.outbuffer = (unsigned char *)Mem_Alloc(tempmempool, width * height * (4+4) + 18);
        gamma = 1.0/scr_screenshot_gammaboost.value;
        dpsnprintf(cls.capturevideo.basename, sizeof(cls.capturevideo.basename), "video/dpvideo%03i", cl_capturevideo_number.integer);
        Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1);
@@ -1167,11 +1236,25 @@ Cr = R *  .500 + G * -.419 + B * -.0813 + 128.;
                SCR_CaptureVideo_RIFF_Write32(0); // color used
                SCR_CaptureVideo_RIFF_Write32(0); // color important
                SCR_CaptureVideo_RIFF_Pop();
+               // master index
+               SCR_CaptureVideo_RIFF_Push("indx", NULL);
+               SCR_CaptureVideo_RIFF_Write16(4); // wLongsPerEntry
+               SCR_CaptureVideo_RIFF_Write16(0); // bIndexSubType=0, bIndexType=0
+               cls.capturevideo.videofile_ix_master_video_inuse_offset = SCR_CaptureVideo_RIFF_GetPosition();
+               SCR_CaptureVideo_RIFF_Write32(0); // nEntriesInUse
+               SCR_CaptureVideo_RIFF_WriteFourCC("00dc"); // dwChunkId
+               SCR_CaptureVideo_RIFF_Write32(0); // dwReserved1
+               SCR_CaptureVideo_RIFF_Write32(0); // dwReserved2
+               SCR_CaptureVideo_RIFF_Write32(0); // dwReserved3
+               cls.capturevideo.videofile_ix_master_video_start_offset = SCR_CaptureVideo_RIFF_GetPosition();
+               for(i = 0; i < AVI_MASTER_INDEX_SIZE * 4; ++i)
+                       SCR_CaptureVideo_RIFF_Write32(0); // fill up later
+               SCR_CaptureVideo_RIFF_Pop();
                // extended format (aspect!)
                SCR_CaptureVideo_RIFF_Push("vprp", NULL);
                SCR_CaptureVideo_RIFF_Write32(0); // VideoFormatToken
                SCR_CaptureVideo_RIFF_Write32(0); // VideoStandard
-               SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.framerate); // dwVerticalRefreshRate (bogus)
+               SCR_CaptureVideo_RIFF_Write32((int)cls.capturevideo.framerate); // dwVerticalRefreshRate (bogus)
                SCR_CaptureVideo_RIFF_Write32(width); // dwHTotalInT
                SCR_CaptureVideo_RIFF_Write32(height); // dwVTotalInLines
                FindFraction(aspect, &n, &d, 1000);
@@ -1222,9 +1305,25 @@ Cr = R *  .500 + G * -.419 + B * -.0813 + 128.;
                        SCR_CaptureVideo_RIFF_Write16(16); // bits per sample
                        SCR_CaptureVideo_RIFF_Write16(0); // size
                        SCR_CaptureVideo_RIFF_Pop();
+                       // master index
+                       SCR_CaptureVideo_RIFF_Push("indx", NULL);
+                       SCR_CaptureVideo_RIFF_Write16(4); // wLongsPerEntry
+                       SCR_CaptureVideo_RIFF_Write16(0); // bIndexSubType=0, bIndexType=0
+                       cls.capturevideo.videofile_ix_master_audio_inuse_offset = SCR_CaptureVideo_RIFF_GetPosition();
+                       SCR_CaptureVideo_RIFF_Write32(0); // nEntriesInUse
+                       SCR_CaptureVideo_RIFF_WriteFourCC("01wb"); // dwChunkId
+                       SCR_CaptureVideo_RIFF_Write32(0); // dwReserved1
+                       SCR_CaptureVideo_RIFF_Write32(0); // dwReserved2
+                       SCR_CaptureVideo_RIFF_Write32(0); // dwReserved3
+                       cls.capturevideo.videofile_ix_master_audio_start_offset = SCR_CaptureVideo_RIFF_GetPosition();
+                       for(i = 0; i < AVI_MASTER_INDEX_SIZE * 4; ++i)
+                               SCR_CaptureVideo_RIFF_Write32(0); // fill up later
+                       SCR_CaptureVideo_RIFF_Pop();
                        SCR_CaptureVideo_RIFF_Pop();
                }
 
+               cls.capturevideo.videofile_ix_master_audio_inuse = cls.capturevideo.videofile_ix_master_video_inuse = 0;
+
                // extended header (for total #frames)
                SCR_CaptureVideo_RIFF_Push("LIST", "odml");
                SCR_CaptureVideo_RIFF_Push("dmlh", NULL);
@@ -1256,6 +1355,7 @@ Cr = R *  .500 + G * -.419 + B * -.0813 + 128.;
                SCR_CaptureVideo_RIFF_Pop();
                // begin the actual video section now
                SCR_CaptureVideo_RIFF_Push("LIST", "movi");
+               cls.capturevideo.videofile_ix_movistart = cls.capturevideo.riffstackstartoffset[1];
                // we're done with the headers now...
                SCR_CaptureVideo_RIFF_Flush();
                if (cls.capturevideo.riffstacklevel != 2)
@@ -1326,50 +1426,43 @@ void SCR_CaptureVideo_EndVideo(void)
        memset(&cls.capturevideo, 0, sizeof(cls.capturevideo));
 }
 
-// converts from RGB24 to I420 colorspace (identical to YV12 except chroma plane order is reversed), this colorspace is handled by the Intel(r) 4:2:0 codec on Windows
-void SCR_CaptureVideo_ConvertFrame_RGB_to_I420_flip(int width, int height, unsigned char *instart, unsigned char *outstart)
+// converts from BGRA32 to I420 colorspace (identical to YV12 except chroma plane order is reversed), this colorspace is handled by the Intel(r) 4:2:0 codec on Windows
+void SCR_CaptureVideo_ConvertFrame_BGRA_to_I420_flip(int width, int height, unsigned char *instart, unsigned char *outstart)
 {
        int x, y;
+       int blockr, blockg, blockb;
        int outoffset = (width/2)*(height/2);
        unsigned char *b, *out;
        // process one line at a time, and CbCr every other line at 2 pixel intervals
        for (y = 0;y < height;y++)
        {
                // 1x1 Y
-               for (b = instart + (height-1-y)*width*3, out = outstart + y*width, x = 0;x < width;x++, b += 3, out++)
-                       *out = cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][b[0]] + cls.capturevideo.rgbtoyuvscaletable[0][1][b[1]] + cls.capturevideo.rgbtoyuvscaletable[0][2][b[2]]];
+               for (b = instart + (height-1-y)*width*4, out = outstart + y*width, x = 0;x < width;x++, b += 4, out++)
+               {
+                       blockr = b[2];
+                       blockg = b[1];
+                       blockb = b[0];
+                       *out = cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
+               }
                if ((y & 1) == 0)
                {
                        // 2x2 Cr and Cb planes
-#if 0
-                       // low quality, no averaging
-                       for (b = instart + (height-2-y)*width*3, out = outstart + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
+                       int inpitch = width*4;
+                       for (b = instart + (height-2-y)*width*4, out = outstart + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 8, out++)
                        {
-                               // Cr
-                               out[0        ] = cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][b[0]] + cls.capturevideo.rgbtoyuvscaletable[1][1][b[1]] + cls.capturevideo.rgbtoyuvscaletable[1][2][b[2]] + 128];
-                               // Cb
-                               out[outoffset] = cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][b[0]] + cls.capturevideo.rgbtoyuvscaletable[2][1][b[1]] + cls.capturevideo.rgbtoyuvscaletable[2][2][b[2]] + 128];
-                       }
-#else
-                       // high quality, averaging
-                       int inpitch = width*3;
-                       for (b = instart + (height-2-y)*width*3, out = outstart + width*height + (y/2)*(width/2), x = 0;x < width/2;x++, b += 6, out++)
-                       {
-                               int blockr, blockg, blockb;
-                               blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
-                               blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
-                               blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
+                               blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
+                               blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
+                               blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
                                // Cr
                                out[0        ] = cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
                                // Cb
                                out[outoffset] = cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
                        }
-#endif
                }
        }
 }
 
-static void SCR_ScaleDown(unsigned char *in, int inw, int inh, unsigned char *out, int outw, int outh)
+static void SCR_ScaleDownBGRA(unsigned char *in, int inw, int inh, unsigned char *out, int outw, int outh)
 {
        // TODO optimize this function
 
@@ -1379,7 +1472,7 @@ static void SCR_ScaleDown(unsigned char *in, int inw, int inh, unsigned char *ou
        // memcpy is faster than me
        if(inw == outw && inh == outh)
        {
-               memcpy(out, in, 3 * inw * inh);
+               memcpy(out, in, 4 * inw * inh);
                return;
        }
 
@@ -1393,7 +1486,7 @@ static void SCR_ScaleDown(unsigned char *in, int inw, int inh, unsigned char *ou
                {
                        float inx0 =  x    / (float)outw * inw; int inx0_i = floor(inx0);
                        float inx1 = (x+1) / (float)outw * inw; int inx1_i = ceil(inx1);
-                       float r = 0, g = 0, b = 0;
+                       float r = 0, g = 0, b = 0, alpha = 0;
                        int xx, yy;
 
                        for(yy = iny0_i; yy < iny1_i; ++yy)
@@ -1402,15 +1495,17 @@ static void SCR_ScaleDown(unsigned char *in, int inw, int inh, unsigned char *ou
                                for(xx = inx0_i; xx < inx1_i; ++xx)
                                {
                                        float a = ya * (min(xx+1, inx1) - max(inx0, xx));
-                                       r += a * in[3*(xx + inw * yy)+0];
-                                       g += a * in[3*(xx + inw * yy)+1];
-                                       b += a * in[3*(xx + inw * yy)+2];
+                                       r += a * in[4*(xx + inw * yy)+0];
+                                       g += a * in[4*(xx + inw * yy)+1];
+                                       b += a * in[4*(xx + inw * yy)+2];
+                                       alpha += a * in[4*(xx + inw * yy)+3];
                                }
                        }
 
-                       out[3*(x + outw * y)+0] = r * area;
-                       out[3*(x + outw * y)+1] = g * area;
-                       out[3*(x + outw * y)+2] = b * area;
+                       out[4*(x + outw * y)+0] = r * area;
+                       out[4*(x + outw * y)+1] = g * area;
+                       out[4*(x + outw * y)+2] = b * area;
+                       out[4*(x + outw * y)+3] = alpha * area;
                }
        }
 }
@@ -1429,11 +1524,11 @@ qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
                if (!cls.capturevideo.videofile)
                        return false;
                // FIXME: width/height must be multiple of 2, enforce this?
-               qglReadPixels (x, y, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo.screenbuffer);CHECKGLERROR
-               SCR_ScaleDown (cls.capturevideo.screenbuffer, vid.width, vid.height, cls.capturevideo.outbuffer, width, height);
+               qglReadPixels (x, y, vid.width, vid.height, GL_BGRA, GL_UNSIGNED_BYTE, cls.capturevideo.screenbuffer);CHECKGLERROR
+               SCR_ScaleDownBGRA (cls.capturevideo.screenbuffer, vid.width, vid.height, cls.capturevideo.outbuffer, width, height);
                in = cls.capturevideo.outbuffer;
-               out = cls.capturevideo.outbuffer + width*height*3;
-               SCR_CaptureVideo_ConvertFrame_RGB_to_I420_flip(width, height, in, out);
+               out = cls.capturevideo.outbuffer + width*height*4;
+               SCR_CaptureVideo_ConvertFrame_BGRA_to_I420_flip(width, height, in, out);
                x = width*height+(width/2)*(height/2)*2;
                SCR_CaptureVideo_RIFF_OverflowCheck(8 + x);
                for (;cls.capturevideo.frame < newframenum;cls.capturevideo.frame++)
@@ -1608,36 +1703,22 @@ static void R_Envmap_f (void)
 
 //=============================================================================
 
-// LordHavoc: SHOWLMP stuff
-#define SHOWLMP_MAXLABELS 256
-typedef struct showlmp_s
-{
-       qboolean        isactive;
-       float           x;
-       float           y;
-       char            label[32];
-       char            pic[128];
-}
-showlmp_t;
-
-showlmp_t showlmp[SHOWLMP_MAXLABELS];
-
 void SHOWLMP_decodehide(void)
 {
        int i;
        char *lmplabel;
        lmplabel = MSG_ReadString();
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
+       for (i = 0;i < cl.num_showlmps;i++)
+               if (cl.showlmps[i].isactive && strcmp(cl.showlmps[i].label, lmplabel) == 0)
                {
-                       showlmp[i].isactive = false;
+                       cl.showlmps[i].isactive = false;
                        return;
                }
 }
 
 void SHOWLMP_decodeshow(void)
 {
-       int i, k;
+       int k;
        char lmplabel[256], picname[256];
        float x, y;
        strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
@@ -1652,41 +1733,37 @@ void SHOWLMP_decodeshow(void)
                x = MSG_ReadShort();
                y = MSG_ReadShort();
        }
-       k = -1;
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               if (showlmp[i].isactive)
-               {
-                       if (strcmp(showlmp[i].label, lmplabel) == 0)
-                       {
-                               k = i;
-                               break; // drop out to replace it
-                       }
-               }
-               else if (k < 0) // find first empty one to replace
-                       k = i;
-       if (k < 0)
-               return; // none found to replace
-       // change existing one
-       showlmp[k].isactive = true;
-       strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
-       strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
-       showlmp[k].x = x;
-       showlmp[k].y = y;
+       if (!cl.showlmps || cl.num_showlmps >= cl.max_showlmps)
+       {
+               showlmp_t *oldshowlmps = cl.showlmps;
+               cl.max_showlmps += 16;
+               cl.showlmps = 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)
+                       Mem_Free(oldshowlmps);
+       }
+       for (k = 0;k < cl.max_showlmps;k++)
+               if (cl.showlmps[k].isactive && !strcmp(cl.showlmps[k].label, lmplabel))
+                       break;
+       if (k == cl.max_showlmps)
+               for (k = 0;k < cl.max_showlmps;k++)
+                       if (!cl.showlmps[k].isactive)
+                               break;
+       cl.showlmps[k].isactive = true;
+       strlcpy (cl.showlmps[k].label, lmplabel, sizeof (cl.showlmps[k].label));
+       strlcpy (cl.showlmps[k].pic, picname, sizeof (cl.showlmps[k].pic));
+       cl.showlmps[k].x = x;
+       cl.showlmps[k].y = y;
+       cl.num_showlmps = max(cl.num_showlmps, k + 1);
 }
 
 void SHOWLMP_drawall(void)
 {
        int i;
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               if (showlmp[i].isactive)
-                       DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
-}
-
-void SHOWLMP_clear(void)
-{
-       int i;
-       for (i = 0;i < SHOWLMP_MAXLABELS;i++)
-               showlmp[i].isactive = false;
+       for (i = 0;i < cl.num_showlmps;i++)
+               if (cl.showlmps[i].isactive)
+                       DrawQ_Pic(cl.showlmps[i].x, cl.showlmps[i].y, Draw_CachePic(cl.showlmps[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
 }
 
 /*
@@ -1706,7 +1783,7 @@ qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *b
                return false;
 
        CHECKGLERROR
-       qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
+       qglReadPixels (x, y, width, height, jpeg ? GL_RGB : GL_BGR, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
 
        if (scr_screenshot_gammaboost.value != 1 && gammacorrect)
        {
@@ -1724,7 +1801,7 @@ qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *b
        if (jpeg)
                ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
        else
-               ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
+               ret = Image_WriteTGABGR_preflipped (filename, width, height, buffer2, buffer3);
 
        return ret;
 }
@@ -1776,7 +1853,7 @@ void SCR_DrawScreen (void)
        R_Mesh_Start();
 
        if (r_timereport_active)
-               R_TimeReport("setup");
+               R_TimeReport("screensetup");
 
        R_UpdateVariables();
 
@@ -2040,7 +2117,8 @@ void CL_UpdateScreen(void)
        qglDepthMask(1);CHECKGLERROR
        qglColorMask(1,1,1,1);CHECKGLERROR
        qglClearColor(0,0,0,0);CHECKGLERROR
-       qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
+       R_ClearScreen();
+       r_view.clear = false;
 
        if(scr_stipple.integer)
        {
@@ -2065,7 +2143,7 @@ void CL_UpdateScreen(void)
                qglDisable(GL_POLYGON_STIPPLE);
 
        if (r_timereport_active)
-               R_TimeReport("clear");
+               R_TimeReport("screenclear");
 
        qglDrawBuffer(GL_BACK);
 
@@ -2123,5 +2201,4 @@ void CL_UpdateScreen(void)
 
 void CL_Screen_NewMap(void)
 {
-       SHOWLMP_clear();
 }