tags:

views:

101

answers:

3

I have written a 2D Jump&Run Engine resulting in a 320x224 (320x240) image. To maintain the old school "pixely"-feel to it, I would like to scale the resulting image by 2 or 3 or 4, according to the resolution of the user.

I don't want to scale each and every sprite, but the resulting image!

Thanks in advance :)

A: 

I'm not exactly sure what you mean by "resulting in ... an image" but if you mean your end result is a texture then you can draw that to the screen and set a scale:

spriteBatch.Draw(texture, position, source, color, rotation, origin, scale, effects, depth);

Just replace the scale with whatever number you want (2, 3, or 4). I do something similar but scale per sprite and not the resulting image. If you mean something else let me know and I'll try to help.

XNA defaults to anti-aliasing the scaled image. If you want to retain the pixelated goodness you'll need to draw in immediate sort mode and set some additional parameters:

spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
GraphicsDevice.SamplerStates[0].MagFilter = TextureFilter.Point;
GraphicsDevice.SamplerStates[0].MinFilter = TextureFilter.Point;
GraphicsDevice.SamplerStates[0].MipFilter = TextureFilter.Point;

It's either the Point or the None TextureFilter. I'm at work so I'm trying to remember off the top of my head. I'll confirm one way or the other later today.

Bob
According to the documentation, `TextureFilter.None` is just for `MipFilter` to disable it (and only use the MagFilter). You probably *do* want to set `MipFilter = TextureFilter.None` for this effect (and leave the others as `Point`).
Andrew Russell
I just looked it up and it is Point that you want
Bob
+1  A: 

Bob's answer is correct about changing the filtering mode to TextureFilter.Point to keep things nice and pixelated.

But possibly a better method than scaling each sprite (as you'd also have to scale the position of each sprite) is to just pass a matrix to SpriteBatch.Begin, like so:

sb.Begin(/* first three parameters */, Matrix.CreateScale(4f));

That will give you the scaling you want without having to modify all your draw calls.

However it is worth noting that, if you use floating-point offsets in your game, you will end up with things not aligned to pixel boundaries after you scale up (with either method).

There are two solutions to this. The first is to have a function like this:

public static Vector2 Floor(Vector2 v)
{
    return new Vector2((float)Math.Floor(v.X), (float)Math.Floor(v.Y));
}

And then pass your position through that function every time you draw a sprite. Although this might not work if your sprites use any rotation or offsets. And again you'll be back to modifying every single draw call.

The "correct" way to do this, if you want a plain point-wise scale-up of your whole scene, is to draw your scene to a render target at the original size. And then draw your render target to screen, scaled up (with TextureFilter.Point).

The function you want to look at is GraphicsDevice.SetRenderTarget. This MSDN article might be worth reading. If you're on or moving to XNA 4.0, this might be worth reading.

I couldn't find a simpler XNA sample for this quickly, but the Bloom Postprocess sample uses a render target that it then applies a blur shader to. You could simply ignore the shader entirely and just do the scale-up.

Andrew Russell
A: 

Thanks for the fast answers! I had to create an account to answer. Well basically both of your answers are great, I'll try passing the Matrix to the Spritebatch first and if that shouldn't work I'll try the other solution! Again, thank you very much :)

Just need to finish my work and get home...

Pumpy
@Gobra: I wanted to know how to upscale the resulting spriteBatch.
Pumpy