May 16, 2009

PyOpenGL 3.0 with py2exe

One of the major hindrances to using PyOpenGL before 3.0 was released (not python 3.0) was that packaging it with py2exe was next to impossible. Thankfully with the release of PyOpenGL 3.0 it is easy. Just include these two imports in one of your project files:

from ctypes import util
try:
from OpenGL.platform import win32
except AttributeError:
pass

That will tell py2exe which part of PyOpenGL to include. Otherwise you have to copy them over manually. Be sure to have the try and except around all win32 imports so your program remains cross platform.

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)