7
\$\begingroup\$

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                                                                                                                                                                        
\$\endgroup\$
12
  • 3
    \$\begingroup\$ 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. \$\endgroup\$
    – DMan
    Commented Nov 27, 2011 at 21:40
  • \$\begingroup\$ Thanks, I'll take a look at that, but I've never used OpenGL before. Kind of new to graphics programming :\ \$\endgroup\$
    – theabraham
    Commented Nov 27, 2011 at 22:30
  • \$\begingroup\$ 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. \$\endgroup\$
    – DMan
    Commented Nov 27, 2011 at 23:09
  • \$\begingroup\$ 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. \$\endgroup\$
    – theabraham
    Commented Nov 28, 2011 at 3:18
  • \$\begingroup\$ 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. \$\endgroup\$
    – DMan
    Commented Nov 28, 2011 at 4:21

3 Answers 3

9
\$\begingroup\$

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
\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$
    – DMan
    Commented Nov 30, 2011 at 1:27
  • \$\begingroup\$ 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 \$\endgroup\$
    – theabraham
    Commented Nov 30, 2011 at 3:15
4
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

Modern pyglet lets you set the default texture filtering by modifying a couple class attributes on Texture. Pyglet docs even explicitly mention "retro style pixel art games".

Here's an example. With the following project structure...

asteroids/
    game/
        __init__.py
        asteroid.py
        player.py
        resources.py
    resources/
        asteroid.png
        flame.png
        spaceship.png
    asteroids.py

...you can have the following code in asteroids.py (the main game logic, where you first import pyglet):

# Set default texture filtering for pixel art.
from pyglet.gl import GL_NEAREST
from pyglet.image import Texture

Texture.default_mag_filter = Texture.default_min_filter = GL_NEAREST

# Do your other imports.
import pyglet

from game import asteroid, player, resources

Now your pixel art scales nicely.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .