# How can I resize pixel art in Pyglet without making it blurry?

I have a tileset of 8x8 pixel images, and I want to resize them in my game so they'd be double that (16x16 pixels, e.g. turning each pixel into a 2x2 block.) What I'm trying to achieve is a Minecraft-like effect, where you have small pixel images scale to larger blockier pixels.

In Pyglet, the sprite's scale property blurs the pixels. Is there some other way?

Working Code:

Here's the solution that works (thanks to DMan's persistence and Jimmy's insight):

image = resource.image('tileset.png')
texture = image.get_texture()
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
texture.width = 16 # resize from 8x8 to 16x16
texture.height = 16
texture.blit(100, 30) # draw

• I'm not familiar with Pyglet enough to make this an answer, but I saw that you can use OpenGL, so from pyglet.gl import * and then make a call to talisman.org/opengl-1.1/Reference/glTexParameter.html with GL_NEAREST. – DMan Nov 27 '11 at 21:40
• Thanks, I'll take a look at that, but I've never used OpenGL before. Kind of new to graphics programming :\ – theabraham Nov 27 '11 at 22:30
• I don't know how much Pyglet does behind the scenes, but something like this could work: glEnable(GL_TEXTURE_2D). Then let's say you had a call to a = image.load('blah.jpg'). Assign tex = a.texture then glBindTexture(GL_TEXTURE_2D, texture.id) and finally a call to pyglet.gl.glTexParameteri(pyglet.gl.GL_TEXTURE_2D, pyglet.gl.GL_TEXTURE_MIN_FILTER, pyglet.gl.GL_NEAREST). I'm not too familiar with the namespace for OpenGL in python, so the I left the full call qualified. Since we imported OpenGL, I believe you can remove at least the pyglet in the front, and maybe gl too. – DMan Nov 27 '11 at 23:09
• Hey I tried it without success, could you double check my code in the update? Also, do you have any good resources to help me understand these GL commands? I appreciate the help. – theabraham Nov 28 '11 at 3:18
• One thing I noticed immediately is that you set the texture width and height before your call to glTexParameteri. OpenGL 1/2/~3 which I presume Pyglet is based on have these immediate mode commands. That is, you execute a command to change the state, then everything after it will change. I'd begin by moving the calls underneath the gl calls. – DMan Nov 28 '11 at 4:21

At the request of commenters...

Warning to Pyglet professionals: There may be a nice Pyglet way to do this, and this isn't it. It's a nice OpenGL way. You have been warned!

You can do this in OpenGL by first binding the texture, then calling glTexParameteri or similar varients. You can do this in Pyglet by importing OpenGL:

from pyglet.gl import *

You can then enable GL_TEXTURE_2D to set the target. This is not always needed, but I'm keeping this complete for some other bindings.

glEnable(GL_TEXTURE_2D)

In Pyglet, it seems like you don't have to bind the texture either. Sometimes you have to load in your image, get the texture id, then use glBindTexture(GL_TEXTURE_2D, texture.id). My assumption that these are already the state set for you in Pyglet.

The next step is to call glTexParameteri. Thanks to Jimmy on correcting me on this: the correct call is:

gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)

A quick break down: the first is just to set the target so OpenGL knows what you're talking about, then the second parameter is the type of filter you would like to set. MAG_FILTER is correct because it controls the magnifications of textures. The final parameter is GL_NEAREST, which controls how the texture is scaled. GL_NEAREST is basically a fast scale that gives pixel-styled textures. GL_LINEAR is normal and will instead smoothly blur your texture.

This version of OpenGL I'm talking about (about < OpenGL 3.2 officially) uses immediate mode, which sets the state. Now that the state is set, you can scale your texture. I can see no better than to show the code that Renold himself posted as working code.

image = resource.image('tileset.png')
texture = image.get_texture()
gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST)
texture.width = 16 # resize from 8x8 to 16x16
texture.height = 16
texture.blit(100, 30) # draw

• Renold, if you could take a look at this and suggest improvements, that'd be great. I'm interested in something though. If you remove texture = image.get_texture(), does that work? It seems like you never called it, unless that binds the texture internally. – DMan Nov 30 '11 at 1:27
• Yeah, turns out you don't need it. I eventually just put the image into a sprite, and it worked fine: image = resource.image('tileset.png') \n sprite = sprite.Sprite(image, x_pos, y_pos) \n sprite.scale = 2 \n – theabraham Nov 30 '11 at 3:15

For those like me, who are simply making a retro-style game where they want EVERYTHING scaled to be pixelated, the simple quick answer is start your code with:

from pyglet.gl import *
glEnable(GL_TEXTURE_2D)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)


Then all your usage of sprites, etc. from there on out stay nice and pixelated.