Skip to main content
GameDev.net gamedev.net
🔒 Locked

Changes in Clear() behaviour

Started by MetaL Feb 19, 2011 at 7:07 AM 2 replies 5.9k views
Original Post
MetaL
MetaL
I finally finished this chapter today. I had problems implementing the split screen. Apparently in earlier XNA versions, the Clear() function just cleared the current viewport, but in XNA 4.0, it clears the whole screen.
The example code needs to be changed a bit due to this - clearing once at the start, and then drawing the top, bottom, and separator viewports. I don't know how to draw a black rectangle to exactly fill the separator viewport yet - I presume we need to set up an orthographic projection matrix (I'm sure it will be covered in the 2D section of the book!) I just omitted the black separator bar for the moment.

This forum discussion explains the changes well.

Shawn Hargreaves' blog has been very helpful for me to explain all the changes in XNA, and this handy 3.1 to 4.0 cheat sheet

Thanks to Jeromy for setting up this workshop too, even though he's busy at the moment, just having a weekly schedule seems to be motivating me more than usual
JWalsh
JWalsh

I finally finished this chapter today. I had problems implementing the split screen. Apparently in earlier XNA versions, the Clear() function just cleared the current viewport, but in XNA 4.0, it clears the whole screen.
The example code needs to be changed a bit due to this - clearing once at the start, and then drawing the top, bottom, and separator viewports. I don't know how to draw a black rectangle to exactly fill the separator viewport yet - I presume we need to set up an orthographic projection matrix (I'm sure it will be covered in the 2D section of the book!) I just omitted the black separator bar for the moment.

This forum discussion explains the changes well.

Shawn Hargreaves' blog has been very helpful for me to explain all the changes in XNA, and this handy 3.1 to 4.0 cheat sheet

Thanks to Jeromy for setting up this workshop too, even though he's busy at the moment, just having a weekly schedule seems to be motivating me more than usual


Hi Metal,

You're correct on all accounts. With XNA 4.0 Microsoft has attempted to more closely mirror the DirectX 11 API. Since DirectX 11 does not support clearing parts of a surface, XNA 4.0 does not support it either. Now calling GraphicsDevice.Clear() will clear the whole screen, not just the viewport, and they've removed the overloads that allowed you to specify regions to clear.

However, there's still a solution. We simply clear the screen to CornflowerBlue at the beginning, use the viewports as usual to draw our two separate displays, and then use the SpriteBatch class with our a run-time generated 2D rectangle in order to draw the separator. The code for that is all in the introduction thread for this week, both here on GameDev.net as well as on my blog.

Cheers!
Michael_B
Michael_B
I want to offer a slight modification to the code posted by JWalsh.

In LoadContent() of Game1.cs in the SplitScreen project is the following code that creates the black texture for the separator viewport:


...
// Original code -->
Color[] texelData = new Color[graphics.GraphicsDevice.Viewport.Width];
for (int i = 0; i < texelData.Length; ++i)
texelData = Color.Black;

separator = new Texture2D(GraphicsDevice, graphics.GraphicsDevice.Viewport.Width, 1);
separator.SetData<Color>(texelData);
// <-- Original code

// Is replaced by
separator = new Texture2D(GraphicsDevice, 1, 1);
separator.SetData<Color>(new Color[1]{ Color.White });
...


And in Draw(...):


...
// Original code
spriteBatch.Draw(separator, Vector2.Zero, Color.Black);

// Is replaced by
spriteBatch.Draw(separator, new Rectangle(0, 0, separatorViewport.Width, separatorViewport.Height), Color.Black);
...


This has the advantage that the texture consists of only 1 pixel. The modified draw call stretches that pixel automatically to whatever size the viewport is set. Furthermore, because the source pixel is white it can now be modulated by the Draw() method to any color. E.g.:


spriteBatch.Draw(separator, new Rectangle(0, 0, separatorViewport.Width, separatorViewport.Height), Color.DarkGoldenrod);
JWalsh
JWalsh
Hi Michael B,

Thanks for posting the alternate solution. I had toyed with posting it myself, but decided against it for a couple reasons. To make it clear to those following along, the solution Michael showed only works if you're flood filling a single color. It doesn't work in the more generic situation of wanting to fill part of the screen with a specific texture, such as a textured background, border, minimap, etc.... In those cases, you need draw the entire texture. So while Michael's solution works well for clearing part of the screen to a single color, I wanted to provide an introduction to drawing 2D in a 3D environment.

Next, we often deal with what's called the time-space trade-off. We're constantly trying to decide which is better - smaller memory footprint, or fewer calculations. This is especially problematic on the Xbox 360 and WinPhone 7 where the .NET Run-Time tends to perform poorly on floating point arithmetic and dynamic memory allocation. By creating a sprite of 1 pixel, it forces the run-time to scale it inside of the Draw method each frame (actually inside of InternalDraw) . It's not much, just a couple multiplication operations, but it's unnecessary if your sprite is the full clear rectangle. Again - this is potentially better for performance, but takes up more memory. And then again, the initial cost to copy the larger texture might even be worse than the multiplications.

And finally, in Michael's example he used....

[color="#1C2837"]
spriteBatch.Draw(separator, new Rectangle(0, 0, separatorViewport.Width, separatorViewport.Height), Color.Black);
You probably want to replace that with.....


spriteBatch.Draw(separator, viewportRectangle, Color.Black);

Creating a new destination rectangle each frame is unnecessary and really bad for the Xbox 360 garbage collector.

So thanks again Michael for posting that shorter and more efficient solution. It works great in this scenario and as with all things, understanding how things work under the hood allows you to get the best performance possible for your specific needs and situation.

Cheers!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.