I was thinking about the best way to scale pixel art. Obviously any non-integral scale factor will produce "bad" results, but I wanted to see if I could come up with something that was better than nearest sampling and linear interpolation. The idea I had was to essentially do anti-aliasing on the image: i.e. treat each pixel of the source image as a square polygon and then draw an output pixel by blending between the source image pixels in proportion to the area of the output pixel that they cover. Here's a result of that line of thought... I think it looks better than both linear and nearest sampling and I think I'm going to use it for my games.

You're going to need a 5.1 branch Allegro to compile this (5.1.6 snapshot works). The code and shaders are in public domain.

To run the example binary you're going to need the D3D runtime installed to use the D3D backend (if you play video games made in this century you'll have it installed most likely), otherwise use allegro.cfg to specify the OpenGL backend ([graphics] driver = opengl).

Looks quite nice in the screenshot but there's something wrong with the y offset here:{"name":"607342","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/b\/8b39f7a5e67af62cd9426259d5425f16.png","w":800,"h":600,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/b\/8b39f7a5e67af62cd9426259d5425f16"}

You know, a similar effect can be achieved by first enlarging with nearest-neighbour filtering by 300% or 400%, then scaling back down with linear filtering. This is the technique I was going to use back when I was considering making some very-low-resolution games.

You know, a similar effect can be achieved by first enlarging with nearest-neighbour filtering by 300% or 400%, then scaling back down with linear filtering. This is the technique I was going to use back when I was considering making some very-low-resolution games.

This is exactly the same, except you first (conceptually) enlarge it infinitely. In fact, this is how I first tested that this might produce something nice. The shader approach has the advantage of using less memory, however.

Doesn't resizing the display cause a device reset? Pretty sure it does. If so, then you have to create shaders and any other GPU resources that Allegro doesn't do for you. So pretty much anything except bitmaps Allegro created.

That is disturbing. I'll have to run these shaders through more stringent tests rather than just compiling for my drivers... hopefully it's some error in the shader and not a fundamental limitation of the approach.

This is exactly the same, except you first (conceptually) enlarge it infinitely. In fact, this is how I first tested that this might produce something nice. The shader approach has the advantage of using less memory, however.

I'll agree on the using less memory thing.

I did discover at one point though that once you expand the image past the size you intend to resize to during enlargement, going any bigger has no effect on the image quality. IE: 320x240 -> 1280x960 -> 1024x768 looks exactly the same as 320x240 -> 2560x1920 -> 1024x768

One advantage to doing it that way is you don't need to use shaders, granted, now that I actually know how to use shaders myself, I don't think I'd go back to not using them for things like this.

I don't know if this is anything like it, but one algorithm that produces pretty good results, especially when scaling up by a small amount is a weighted average scale. It'd probably be easy and fast with a shader...

Basically say for example you're scaling up by 1/4, so an extra pixel for every 3 pixels... the 4th pixel would be 1/2 taken from the 3rd pixel and 1/2 taken from the 5th (IIRC, it's been a while since I implemented it.)

It doesn't produce very much blur, at least compared to linear filtering.

Peter, could you re-download the shaders and try again? I altered how the texture sampling happens... it fixed my issues with D3D, so it might fix them for you as well.

Works.

Attached screenshots from a quick-ish hack of Dune Dynasty, 1.5x zoom. It's supposed have no effect at integer scales, yes? (Don't worry about the elements outside the game viewport; those are drawn at scale=2.0 but using the shader with scale=1.5.)