2
\$\begingroup\$

I came up with the following class that I can use as an XNA service to manage rendering to things other than the screen as I didn't want to be passing Games/GraphicsDevices around all over the place for testing reasons. I can't see anything wrong with it, but I'm curious what other people think about the design/etc. of it and the general theory of it. Is this abusing IDisposable, or is this an ok way to do things?

Typical Usage:

using(Services.GetService<IRenderTargetController>().SetRenderTarget(renderTarget, Color.Black)) {
    // [snip] Render stuff as normal here.
}

Implementation:

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

sealed class RenderTargetController : IRenderTargetController
{
    private readonly GraphicsDevice _graphicsDevice;
    private readonly Stack<RenderTarget2D> _targets;

    public RenderTargetController(GraphicsDevice graphicsDevice)
    {
        _graphicsDevice = graphicsDevice;
        _targets = new Stack<RenderTarget2D>();
    }

    public IDisposable SetRenderTarget(RenderTarget2D target)
    {
        return SetRenderTarget(target, Color.Transparent);
    }

    public IDisposable SetRenderTarget(RenderTarget2D target, Color resetColor)
    {
        _targets.Push(target);
        _graphicsDevice.SetRenderTarget(target);
        _graphicsDevice.Clear(resetColor);

        return new TargetManager(this);
    }

    private class TargetManager : IDisposable
    {
        private readonly RenderTargetController _controller;

        public TargetManager(RenderTargetController controller)
        {
            _controller = controller;
        }

        public void Dispose()
        {
            _controller._targets.Pop();

            RenderTarget2D target = null;
            if (_controller._targets.Count > 0)
            {
                target = _controller._targets.Peek();
            }

            // Setting render target to null returns control to the screen.
            _controller._graphicsDevice.SetRenderTarget(target);
        }
    }
}
\$\endgroup\$
2
\$\begingroup\$

An approach itself is fine IMO, but the API is misleading. Why would SetXXX method ever return something, let alone return an IDisposable? Maybe come up with a better name.

\$\endgroup\$
2
  • \$\begingroup\$ The approach reminds me of the way an observable (Rx observer/observable pattern) returns an IDisposable when the observables' Subscribe method is called ...might help in determining a better name for the method. \$\endgroup\$ – IAbstract Sep 2 '11 at 11:36
  • \$\begingroup\$ @IAbstract: In my head, I actually likened it more to a transaction based system. When you call SetRenderTarget you are opening a transaction which is returned and kept open till it is disposed. Naming is hard though, and I can't quite think of what it should be named instead. \$\endgroup\$ – Matthew Scharley Sep 2 '11 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.