Home

Fixing blurry images

2D games in Rust with ggez

TL; DR - if you are making a pixel art game with rust + ggez and scaling the textures, then you probably want to set the default filtering to Nearest, with the line

graphics::set_default_filter(ctx, graphics::FilterMode::Nearest);

The problem

This basic ggez example that draws an image to the screen.

use ggez;
use ggez::event;
use ggez::graphics;
use ggez::nalgebra;
use ggez::{Context, GameResult};

struct MainState {
    image: graphics::Image,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let s = MainState {
            image: graphics::Image::new(ctx, "/character.png")?,
        };
        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        graphics::draw(
            ctx,
            &self.image,
            graphics::DrawParam::new().scale(nalgebra::Vector2::new(3.0, 3.0)),
        )?;
        graphics::present(ctx)?;
        Ok(())
    }
}

pub fn main() -> GameResult {
    let cb = ggez::ContextBuilder::new("pixel art example", "ggez");
    let (ctx, event_loop) = &mut cb.build()?;
    let state = &mut MainState::new(ctx)?;
    event::run(ctx, event_loop, state)
}

The result is not what you might expect if you're looking for crisp pixel art. You end up with the blurry image below.

Blurry character
Blurry character

There are two ways around this.

Set the default filtering mode for all images to FilterMode::Nearest

pub fn main() -> GameResult {
    let cb = ggez::ContextBuilder::new("pixel art example", "ggez");
    graphics::set_default_filter(ctx, graphics::FilterMode::Nearest);
    let (ctx, event_loop) = &mut cb.build()?;
    let state = &mut MainState::new(ctx)?;
    event::run(ctx, event_loop, state)
}

Set the filter mode on an image by image basis

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let mut image = graphics::Image::new(ctx, "/map.png")?
        image.set_filter(graphics::FilterMode::Nearest);
        let s = MainState { image };
        Ok(s)
    }
}

Result

In our example, since we're only drawing a single image, the result is the same, nice crisp, non-blurry pixel art!

Crisp character
Crisp character

Links

Code for this article is available at GitHub - joetsoi/ggez-tutorials in the blurry directory.

Meta

Code tested on