[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] Using PyOpenGL for 2D graphics
kschnee@xxxxxxxxxx:
I use python-ogre, which is a more recent much better version of pyogre by a different team. Cegui works with it and is pretty nice, although feels like overkill for most things. I have never really looked at sprites or any kind of 2d stuff with it though, our game is completely 3d. As a robust 3d rendering engine, nothing else I know of comes close, at least out of things usable from python. It surely has a learning curve though, and its quite big (which can be a positive and a negative).
Fonts in opengl aren't too difficult, neither is rendering an interface. You will want to render the interface AFTER you render all the 3d elements, and turn off the depth buffer before you render it so it is rendered on top of everything. There are numerous font systems around, I use some code treeform gave me on irc which I modified for pygame. I attached it for you. Openglcontext which is somewhat of an addon for pyopengl also has font code. Lastly, I once programmed my own font system using the NeHe tutorial as a guide - it was confusing because there is so much windows api specific code in that tutorial, but the basic idea is the same - load each letter of the font as a texture and draw quads with the proper texture.
I attached this code as well, although this is not as well tested or clear.
import pygame
pygame.font.init()
from OpenGL.GL import *
from OpenGL.GLU import *
#from mygl.texture.material import *
def nextPowerOf2 (num):
""" If num isn't a power of 2, will return the next higher power of two """
rval = 1
while (rval<num):
rval <<= 1
return rval
def setupMatrix():
""" sets up the matrix for font drawing """
glPushAttrib(GL_TRANSFORM_BIT)
viewport = glGetIntegerv(GL_VIEWPORT)
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3])
glPopAttrib()
def taredownMatrix():
""" returns the matrix to the state before setupMatrix """
glPushAttrib(GL_TRANSFORM_BIT)
glMatrixMode(GL_PROJECTION)
glPopMatrix()
glPopAttrib()
class Font:
""" very nice font class """
def __init__ (self, name, height=10,antialias=True):
""" make a font with font name and font hight """
self.m_allocated = True
self.height = height
self.name = name
self.antialias = antialias
self.sizes = {}
ft = pygame.font.Font(name,height)
self._listStart = glGenLists (128)
self.fontTextures = [None] * 128
for i in xrange (128):
self._makeList (ft, i, self._listStart, self.fontTextures);
ft = None
def setup(self):
glPushMatrix()
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT)
glMatrixMode(GL_MODELVIEW)
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glDisable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
def tairdown(self):
glPopAttrib()
glPopMatrix()
def printChar(self,character):
glCallList(character+self._listStart)
def flatPrint (self, string):
""" the normal print of a font """
if (string == None or string == "" ):
return
glPushMatrix()
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT)
glMatrixMode(GL_MODELVIEW)
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glDisable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
#glListBase(self._listStart)
glPushMatrix ()
#glCallLists (string)
for char in string:
glCallList(self._listStart+ord(char))
glPopMatrix()
glPopAttrib()
glPopMatrix()
def wrapPrint(self , string, size=(0,0) ):
""" prints text in the sized window """
lines = string.split ( "\n" )
glPushMatrix()
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT)
glMatrixMode(GL_MODELVIEW)
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glDisable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
#glListBase(self._listStart)
h = self.sizes["A"][1]
print self._listStart
for i in xrange (len (lines)):
line = lines [i]
if self.getTextSize(line)[0] > size:
width = 0
liner = ""
for c in line:
if width + self.sizes[c][0] < size:
liner += c
width += self.sizes[c][0]
else:
glPushMatrix ()
#glCallLists(liner) # hope this gets fixed
for character in liner:
glCallList(self._listStart+ord(character))
glPopMatrix()
glTranslatef (0, h ,0);
liner = c
width = 0
if liner != "":
glPushMatrix ()
#glCallLists (liner) # hope this gets fixed
for character in liner:
glCallList(self._listStart+ord(character))
glPopMatrix()
glTranslatef (0, h ,0);
else:
if len(line) > 0:
glPushMatrix ()
for character in line:
glCallList(self._listStart+ord(character))
glPopMatrix()
glTranslatef (0, h ,0);
glPopAttrib()
glPopMatrix()
glEnable(GL_DEPTH_TEST)
glDisable(GL_BLEND)
def _makeList (self,ft, ch, list_base, tex_base_list):
"""
makes the font list
"""
try:
a = ft.render(chr(ch),self.antialias,[220,225,225])
b = ft.render(chr(ch),self.antialias,[40,40,40])
a = pygame.transform.rotozoom(a,0,.9)
b.blit(a,[1,1])
glyph = b
except:
glyph = ft.render('\n',0,[255,255,255])
glyphWidth, glyphHeight = glyph.get_size()
ratio = glyphHeight/self.height
glyphWidth *= ratio
glyphHeight *= ratio
self.sizes[chr(ch)] = [glyphWidth,glyphHeight]
width = nextPowerOf2 (glyphWidth + 1)
height = nextPowerOf2 (glyphHeight + 1)
glyph = pygame.transform.scale(glyph,[width,height])
expandedData = pygame.image.tostring(glyph,
"RGBA",True)
ID = glGenTextures (1)
tex_base_list [ch] = ID
glBindTexture (GL_TEXTURE_2D, ID)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, expandedData )
expandedData = None
glNewList (list_base + ch, GL_COMPILE)
if (ch == ord (" ")):
glyph_advance = glyphWidth
glTranslatef(glyph_advance, 0, 0)
glEndList()
else:
glBindTexture (GL_TEXTURE_2D, ID)
glPushMatrix()
glBegin(GL_QUADS)
glTexCoord2f(0,0), glVertex2f(0,0)
glTexCoord2f(0,1), glVertex2f(0,glyphHeight)
glTexCoord2f(1,1), glVertex2f(glyphWidth,glyphHeight)
glTexCoord2f(1,0), glVertex2f(glyphWidth,0)
glEnd()
glPopMatrix()
glTranslatef(glyphWidth , 0, 0) #+ 0.75
glEndList()
def release (self):
""" Release the gl resources for this Face.
(This provides the functionality of KillFont () and font_data::clean ()
"""
if (self.m_allocated):
# Free up the glTextures and the display lists for our face
glDeleteLists ( self._listStart, 128);
for ID in self.fontTextures:
glDeleteTextures (ID);
# Extra defensive. Clients that continue to try and use this object
# will now trigger exceptions.
self.list_base = None
self.m_allocated = False
return
def getTextSize(self , text ="" ):
"""
returns the size of a string text
if you do not give a string it returns the (0,hight) of the font
"""
if text == "":
return (0,self.sizes["A"][1])
w = 0
h = 0
for c in text:
w += self.sizes[c][0]
if self.sizes[c][1] > h:
h = self.sizes[c][1]
return (w,h)
def __del__ (self):
""" Python destructor for when no more refs to this Face object """
self.release ()
return
import pygame
pygame.display.set_mode([100,100])
import random
import math
from OpenGL.GL import *
from OpenGL.GLU import *
class bitmapfont:
def __init__(self):
self.base = glGenLists(96)
pygame.font.init()
self.font = pygame.font.SysFont("Courier New",24,0,0)
self.characters = []
self.tnames = glGenTextures(94)
for i in range(32,32+94):
char = self.font.render(chr(i),True,[255,255,255]).convert_alpha()
char = pygame.transform.scale(char,[32,32])
s = pygame.Surface([char.get_width(),char.get_height()])
s.fill([0,0,0])
s.blit(char,[0,0])
#s = pygame.image.load("Data/Cube.bmp")
if chr(i)=='a':
pygame.image.save(s,"tst.tga")
#self.characters.append(s)
glBindTexture(GL_TEXTURE_2D,self.tnames[i-32])
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
idat = pygame.image.tostring(s,"RGBA",True)
glTexImage2D(GL_TEXTURE_2D,0,4,s.get_width(),s.get_height(),0,GL_RGBA,GL_UNSIGNED_BYTE,idat)
#make a display list for the character
glNewList(self.base+i,GL_COMPILE)
glBindTexture(GL_TEXTURE_2D,self.tnames[i-32])
glBegin(GL_QUADS)
glTexCoord2d(0,0);glVertex3f(0,0,0)
glTexCoord2d(1,0);glVertex3f(.05,0,0)
glTexCoord2d(1,1);glVertex3f(.05,.1,0)
glTexCoord2d(0,1);glVertex3f(0,.1,0)
glEnd()
glTranslatef(.05,0,0)
glEndList()
def write(self,text):
glPushAttrib(GL_LIST_BIT)
glListBase(self.base)
#~ for c in text:
#~ glCallList(ord(c)-31)
glCallLists(text)
glPopAttrib()
class Screen:
def __init__(self):
self.wi = 640
self.hi = 480
self.fullscreen = 0
self.caption = "Nehe lesson 13 Bitmap Text"
self.glinited = False
self.texloaded = False
self.tnames = []
self.textures = []
#instance variables to be replaced with objects
self.bfont = None
self.c1 = 0
self.c2 = 0
def initGL(self):
glEnable(GL_TEXTURE_2D)
glShadeModel(GL_SMOOTH)
glClearColor(0,0,0,0)
glClearDepth(1.)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)
#glEnable(GL_LIGHT0)
#glEnable(GL_LIGHTING)
glEnable(GL_COLOR_MATERIAL)
#glEnable(GL_BLEND)
#glBlendFunc(GL_SRC_ALPHA,GL_ONE)
self.bfont = bitmapfont()
def resize(self):
wi,hi,fullscreen = self.wi,self.hi,self.fullscreen
self.screen = pygame.display.set_mode([wi,hi],pygame.OPENGL|pygame.DOUBLEBUF|pygame.FULLSCREEN*fullscreen|pygame.RESIZABLE)
pygame.display.set_caption(self.caption)
if hi==0: hi = 1
glViewport(0,0,wi,hi)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.,float(wi)/float(hi),.1,100.)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if not self.glinited: self.initGL()
def draw(self):
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0,0,-3)
glColor3f(math.cos(self.c1),math.sin(self.c2),1-.5*math.cos(self.c1+self.c2))
glTranslatef(.5*math.cos(self.c1),.35*math.sin(self.c2),0)
#self.bfont.write("Active OpenGL Text With NeHe - %7.2f"%self.c1)
self.bfont.write("I wonder how long a line I can write")
self.c1 += .051
self.c2 += .005
screen = Screen()
screen.resize()
piover180 = math.pi/180.0
running = 1
c = pygame.time.Clock()
while running:
c.tick(60)
screen.draw()
pygame.display.flip()
for e in pygame.event.get():
if e.type==pygame.VIDEORESIZE:
screen.wi,screen.hi = e.w,e.h
screen.resize()
if e.type==pygame.KEYDOWN:
if e.key==pygame.K_ESCAPE:
running = 0
if e.key==pygame.K_RETURN:
screen.wi,screen.hi,screen.fullscreen=40,40,0
screen.resize()
keys = pygame.key.get_pressed()
if keys[pygame.K_PAGEUP]:
pass
if keys[pygame.K_PAGEDOWN]:
pass
if keys[pygame.K_RIGHT]:
pass
if keys[pygame.K_LEFT]:
pass
if keys[pygame.K_UP]:
pass
if keys[pygame.K_DOWN]:
pass