Formeln

Sunday, November 3, 2013

Making a Screenshot with SlimDX

Making a Screenshot with SlimDX


Making a screenshot is rather simple with SlimDX. In general, you take
the render surface, read its content and save it to a file.
Luckily, there is a function for this in the SDK:

SlimDX.Direct3D11.Resource.SaveTextureToFile

This is a code fragment using this method:


 SlimDX.Direct3D11.Resource.SaveTextureToFile(dm.context,
          dm.renderTarget.Resource,
          SlimDX.Direct3D11.ImageFileFormat.Jpg,
          "screenshot.jpg");

You can make a function to encapsulate the call and call this function at the end of your render loop.
I made it this way:


public void RenderScene()
{
  while (true)
  {
    if (resize)
    {
      DeviceManager.Instance.Resize();
      resize = false;
    }

    fc.Count();

    DeviceManager dm = DeviceManager.Instance;
      dm.context.ClearDepthStencilView(dm.depthStencil,
      DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil,
      1.0f,
      0);

    dm.context.ClearRenderTargetView(dm.renderTarget,
      new Color4(0.75f, 0.75f, 0.75f));

    Scene.Instance.Render();

    dm.swapChain.Present(syncInterval, PresentFlags.None);

    if (makeScreenshot)
    {
      screenShots.MakeScreenshot(DeviceManager.Instance, ImageFileFormat.Jpg);
      makeScreenshot = false;
    }
  }
}

The boolean value makeScreenshot has to be triggered from outside this class, for example
from you GUI code. The screenshot is made with the current width and height of the render window.

If you want to capture the frame in an other resolution, you have to render the scene to the render surface,
reset and resize the buffers to the wanted resolution, write the screenshot and then resize the buffers
back to the current resolution of the window you are rendering to.

This is, how my helper method looks, for rendering a screenshot with a different resolution:


public void MakeScreenshot(DeviceManager dm, Scene scene, int width, int height, SlimDX.Direct3D11.ImageFileFormat format, string fileName)
{
  try
  {
    Viewport OriginalViewport = dm.viewport;
    dm.Resize(width, height);
    dm.context.ClearDepthStencilView(dm.depthStencil,
      DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil,
      1.0f, 0);
    dm.context.ClearRenderTargetView(dm.renderTarget,
      new Color4(0.75f, 0.75f, 0.75f));
    scene.Render();

    SlimDX.Direct3D11.Resource.SaveTextureToFile(dm.context,
      dm.renderTarget.Resource,
      format,
      fileName +  "." + format.ToString());

      dm.Resize((int)OriginalViewport.Width, (int)OriginalViewport.Height);
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.ToString());
    }
  }
}

This is, for example, a screenshot with a resolution of 3000x2000:


When using the png format, the colors are somehow false. I don't know if it is problem in the
SDK or if I am using a wrong format.