4
\$\begingroup\$

I have an app that plays back a video and draws the video onto the screen at a moving position. When I run the app, the video moves around the screen as it plays. Here is my Draw method...

    protected override void Draw(GameTime gameTime)
    {
        Texture2D videoTexture = null;

        if (player.State != MediaState.Stopped)
            videoTexture = player.GetTexture();

        if (videoTexture != null)
        {
            spriteBatch.Begin();
            spriteBatch.Draw(
                    videoTexture,
                    new Rectangle(x++, 0, 400, 300),  /* Where X is a class member */
                    Color.White);
            spriteBatch.End();
        }

        base.Draw(gameTime);
    }

The video moves horizontally acros the screen. This is not exactly as I expected since I have no lines of code that clear the screen. My question is why does it not leave a trail behind?

Also, how would I make it leave a trail behind?

\$\endgroup\$
3
  • \$\begingroup\$ Out of curiosity, why would you want the video to smear across the screen that way? \$\endgroup\$
    – user1430
    Feb 10, 2011 at 7:38
  • \$\begingroup\$ It's not for a game, but rather to produce a type of graphics effect. Imagine a video of someone's head rotating. If you smear this video and clip it so that one half of the video is not drawn, you will plot an image of their head 'unwrapped' so to speak. Then take a screenshot and paste into photoshop to use elsewhere. I guess it might be a way to make a texture map of someone's head, game-wise. \$\endgroup\$
    – izb
    Feb 13, 2011 at 11:20
  • 1
    \$\begingroup\$ .. And see my avatar for the effect :) \$\endgroup\$
    – izb
    Feb 14, 2011 at 10:51

3 Answers 3

1
\$\begingroup\$

Drawing in the screen is much more than just drawing in it. A system called "double buffering" is commonly used. In double buffering, you have two canvases: a front and a back one.

Whenever you're drawing, you draw onto the back canvas, and when you're done and ready to show it into the screen, you flip the back and front canvases. If canvases weren't cleared automatically before you started drawing on them, you'd end with even frame trails on one canvas and odd frame trails on the other. Sometimes the back canvas is cleared by the video card when you flip it, sometimes it's not. Sometimes it's actually filled with garbage so you can know you didn't clear it.

However, that is not the only way to implement a graphics pipeline. There are many more, such as triple buffering, and many more esoteric ones. So you should never assume anything about data you don't explicitly save from one frame to another.

Instead, if you want to have trails as you explained, you should capture your output, store it, and when you start the next frame, draw it at the very back.

\$\endgroup\$
1
  • \$\begingroup\$ This turned out to be the working answer. You need to get the back buffer data and then draw it back onto the screen before drawing anything else. \$\endgroup\$
    – izb
    Feb 14, 2011 at 10:51
4
\$\begingroup\$

Just a bit of a guess here (after answering this question): It's possible that the video renderer is clearing the graphics memory. Perhaps it has to emulate a quirk of the Xbox GPU hardware to remain consistent on Windows. I'm not entirely sure.

But try using:

GraphicsDeviceManager.PreparingDeviceSettings

to modify:

GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage

And setting it to RenderTargetUsage.PreserveContents.


I'm pretty sure you don't need to fiddle with BeginDraw (as Josh mentioned). Unless you've change it yourself, it should have no effect.

However you should be aware of double-buffering (as Oscar mentions) - this will probably cause the trail your video leaves behind to flicker. The simple way to solve this is to disable double-buffering. The more complicated way is to use render targets (as Roy mentions) to store your video trail (this also solves the clearing problem).

\$\endgroup\$
5
  • \$\begingroup\$ Yup, I don't know what I was thinking when I posted my answer that you are referring to -- it was blatantly wrong, so I've deleted it. Thanks for the correction :D \$\endgroup\$
    – user1430
    Feb 10, 2011 at 16:53
  • \$\begingroup\$ I'd really advice against disabling double buffering or messing with anything in your device configuration in order to get graphical effects to work. If you want trailing, it should work because its' an integral part of your drawing algorithm, not because it's a side effect of the device configuration. \$\endgroup\$
    – slcpfmmm
    Feb 11, 2011 at 5:27
  • \$\begingroup\$ @Oscar There's nothing at all "evil" about selecting a graphics device setup that makes a core effect work, as long as you are aware of the trade-offs involved (and admittedly there are some fairly serious downsides to the simple, disable-the-double-buffer approach). \$\endgroup\$ Feb 11, 2011 at 8:11
  • \$\begingroup\$ It depends. Usually the behavior of side effects of certain device configurations are not standard across vendors, devices and even driver versions. So you're risking a great deal in portability. The trade-offs are usually unknown and unpredictable, so unless you're doing a prototype, or you can guarantee a specific hardware model/driver version (such as for console or arcade development), I'd strongly advice against side-effect programming. This site has a nice explanation with an example: webster.cs.ucr.edu/AoA/Windows/HTML/… \$\endgroup\$
    – slcpfmmm
    Feb 15, 2011 at 2:53
  • \$\begingroup\$ Treating a buffer as a single buffer by configuring it as single buffer is clearly not a "side-effect". Don't be stupid. But this whole thing is moot - because it looks like you can't actually disable double-buffering in XNA anyway. \$\endgroup\$ Feb 15, 2011 at 7:17
0
\$\begingroup\$

This will probably give you the correct effect without having to override BeginDraw which as Oscar Rodriguez rightfully said, is a bad idea.

RenderTarget2D smearRT;

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Black);

    Texture2D videoTexture = null;

    if (player.State != MediaState.Stopped)
        videoTexture = player.GetTexture();

    if (videoTexture != null)
    {
        GraphicsDevice.SetRenderTarget(smearRT);
        spriteBatch.Begin();
        spriteBatch.Draw(
                videoTexture,
                new Rectangle(x++, 0, 400, 300),  /* Where X is a class member */
                Color.White);
        spriteBatch.End();
        GraphicsDevice.SetRenderTarget(null);
    }

    spriteBatch.Begin();
    spriteBatch.Draw(smearRT, new Rectangle(0,0, 800, 600), Color.White);
    spriteBatch.End();

    base.Draw(gameTime);
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .