Threaded Screenshot Capture

From XNAWiki
Jump to: navigation, search

Intro

Screenshots tend to lag up the game solely because of the physical file saving aspect. The file output usually take about a second and you will definitely notice the slight pause.

Screenshot Class

Here's a class to work around that saving lag:

Note: Because of the ResolveTexture2D is being created with Bgr32 SurfaceFormat, it fixes the PNG alpha blending issue of alpha blended sprites looking brighter than they should.

using System;
using System.IO;
using System.Windows.Forms;
using System.Threading;
 
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
 
namespace LOLNAMESPACELOL
{
    public class Screenshot
    {
        private ResolveTexture2D screenshotRT;
        private string screenshotPath;
 
        public Screenshot()
        {
            screenshotPath = System.Windows.Forms.Application.StartupPath + "\\screenshots";
            if (!System.IO.Directory.Exists(screenshotPath))
                System.IO.Directory.CreateDirectory(screenshotPath);
        }
 
        public void TakeScreenshot(GraphicsDevice device)
        {
            int w = device.PresentationParameters.BackBufferWidth;
            int h = device.PresentationParameters.BackBufferHeight;
 
            screenshotRT = new ResolveTexture2D(device, w, h, 1, SurfaceFormat.Bgr32);
 
            device.ResolveBackBuffer(screenshotRT);
 
            Thread newThread = new Thread(ScreenshotThread);
            newThread.Start();
        }
 
        private void ScreenshotThread()
        {
            if (!screenshotRT.IsDisposed)
            {
                string timestampName = DateTime.Now.ToString("yyyyMMdd_HHmmss");
 
                int i = 1;
                string screenshotPostfix = "";
                while (File.Exists(String.Format("{0}\\{1}{2}.png", screenshotPath, timestampName, screenshotPostfix)))
                {
                    screenshotPostfix = " (" + i + ")";
                    i++;
                }
 
                string filename = String.Format("{0}\\{1}{2}.png", screenshotPath, timestampName, screenshotPostfix);
 
                screenshotRT.Save(filename, ImageFileFormat.Png);
 
                screenshotRT.Dispose();
            }
        }
    }
}

How to use in your game

To use this class you have to create a new Screenshot, and pass the GraphicsDevice to TakeScreenshot()

Screenshot screenShot
 
// other stuff you normally have here....
 
protected override void Initialize()
{
    base.Initialize();
    screenShot = new Screenshot();
}

To actually take a screenshot:

screenshot.TakeScreenshot(GraphicsDevice);