Zune landscape mode


My Zune Freecell game runs in 320×240 landscape mode, rather than the default 240×320 portrait orientation.

Unfortunately, the XNA Framework does nothing to help you render rotated scenes.

Fortunately, you can do this rather easily by drawing everything to a rendertarget, then rotating that as a postprocess.

But unfortunately, copying the entire scene via a rendertarget didn’t meet my power efficiency goals.

The most efficient way to do any task is to find some way to avoid the need to do it at all. If I rotate my textures ahead of time during the Content Pipeline build process, my game code will not need to bother rotating them at runtime on the Zune. So I wrote this custom Content Processor:

    [ContentProcessor]
public class RotatedTextureProcessor : TextureProcessor
{
public override TextureContent Process(TextureContent input, ContentProcessorContext context)
{
if (context.TargetPlatform == TargetPlatform.Zune)
{
input.ConvertBitmapType(typeof(PixelBitmapContent<Color>));

for (int i = 0; i < input.Faces.Count; i++)
{
for (int j = 0; j < input.Faces[i].Count; j++)
{
PixelBitmapContent<Color> source = (PixelBitmapContent<Color>)input.Faces[i][j];
PixelBitmapContent<Color> dest = new PixelBitmapContent<Color>(source.Height, source.Width);

for (int x = 0; x < dest.Width; x++)
{
for (int y = 0; y < dest.Height; y++)
{
dest.SetPixel(x, y, source.GetPixel(y, source.Height - x - 1));
}
}

input.Faces[i][j] = dest;
}
}
}

return base.Process(input, context);
}
}

Of course it is not enough to just rotate the contents of each texture: I also need to change the coordinates where I draw them on the screen. I did this by tweaking my SpriteBatch class:

    class Renderer : SpriteBatch
{
new public void Draw(Texture2D texture, Vector2 position, Color color)
{
#if ZUNE
position = new Vector2(240 - texture.Width - position.Y, position.X);
#endif
base.Draw(texture, position, color);
}
}

Comments (6)

  1. BillReiss says:

    Hi Shawn, why not just do a Transform matrix on the SpriteBatch.Begin which does a rotate and a translate? I’ve done this before and it works pretty well. Is this technique better for performance reasons?

    Thanks,

    Bill Reiss

  2. ShawnHargreaves says:

    Great point – I forgot all about the transform matrix approach!

    That will be much more efficient than using a rendertarget (because it avoids having to copy the entire scene an extra time) but a little less efficient than precomputing the rotations (because it does still require the runtime drawing code to apply the rotation logic, and even though a 90 degree rotation is algorithmically trivial, this will be much less cache friendly as the source and destination are not layed out the same way in memory).

  3. kewlniss says:

    Also I have seen it to actually stretch / skew the sprite font text when used.

    I definitely like the content pipeline approach here.

    Thanks Shawn!

    Chad

  4. Grant says:

    I realize this is old, but I’m rather new to programming and I need some help with how to implement this.

    So, I have the Content Pipeline Extension included in the solution, and I don’t see much more to do with that.

    The thing that confuses me is the spritebatch tweaking.  I’ve created the Renderer class as you have shown here, but how should I call it?  Specifically, how should I load it?  Right now, I’ve basically replaced "SpriteBatch" with "Renderer" in my code, and it doesn’t like it.  "renderer = new Renderer(GraphicsDevice);" doesn’t work, obviously, because it’s not set up to take an argument.  So I removed the argument.  Still, in the Renderer.cs itself, it says that SpriteBatch does not contain a constructor that takes ‘0’ arguments.

  5. Abbu says:

    Hey Grant,

    I think the Renderer needs a constructor that passes the GraphicsDevice to it's base class constructor.

    Something like "public Renderer(GraphicsDevice graphicsDevice) : base(graphicsDevice) {}" should do.

  6. blondie says:

    Todau when I logged on, my whole screen orientation was rotated to landscape.  how do i move the orientation back one rotationclockwise to have my normal set up?