May 7, 2009

Better pygame and rabbyt texture loading

For one of my current projects I'm using rabbyt in conjunction with pygame. With the default texture loading, if your image dimensions are not powers of two your resulting sprite will be blurry. Pyglet fixes this by creating a new texture with correct dimensions, blitting your image onto the texture and then setting the texture coordinates. That way OpenGL doesn't do its blurry scaling job on your image.

Well, pygame's texture loading doesn't do that. So you either go to great pains to make sure all your textures are powers of two (which can be annoying when you don't want your sprites to be those sizes) or do the coordinate mapping manually.

Here is a custom texture loading hook that does this on all textures when you load them:
from __future__ import division
import pygame, rabbyt, sys, os
from rabbyt._rabbyt import load_texture

def next_pow2( n ):
"""
Find the next power of two.
"""
n -= 1
n = n | (n >> 1)
n = n | (n >> 2)
n = n | (n >> 4)
n = n | (n >> 8)
n = n | (n >> 16)
n += 1
return n


class Tex:
def __init__(self):
self.id = 0
self.width = 0
self.height = 0
self.tex_coords = (0,0,0,0)

_texture_cache = {}
def load_and_size(filename, filter=True, mipmap=True):
if filename not in _texture_cache:
pygame = __import__("pygame", {},{},[])
if os.path.exists(filename):
img = pygame.image.load(filename)
else:
img = pygame.image.load(os.path.join(data_directory, filename))

t = Tex()
t.width,t.height = size = list(img.get_size())
size[0] = next_pow2(size[0])
size[1] = next_pow2(size[1])
t.tex_coords = (0,t.height/size[1],t.width/size[0],0)

n = pygame.Surface(size, pygame.SRCALPHA|pygame.HWSURFACE, img)
n.blit(img, (0,size[1]-t.height))

data = pygame.image.tostring(n, 'RGBA', True)
t.id = load_texture(data, size, "RGBA", filter, mipmap)
_texture_cache[filename] = t
return _texture_cache[filename]

rabbyt.set_load_texture_file_hook(load_and_size)

No comments:

Post a Comment