[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: framework proposal - was Re: [pygame] Re: Distribution of Work



On Wed, 8 Oct 2003, Richard Jones wrote:
> On Wed, 8 Oct 2003 09:54 am, Jasper Phillips wrote:
> > Basically I've got a python module for using a pygame surface as a
> > texture on an openGL quad, moving it arround, and updating changed areas
> > of the texture corresponding to sprite blits.
> >
> > I'm use this for a scrollable/zoomable map/unit display in a turn based
> > game, where I get 60+ FPS while scrolling, although I'm not animating
> > units so the texture doesn't change frequently.  Still, since textures
> > only update rectangles that have changed, it shouldn't be too bad.
> 
> Please, share the code even if only person-to-person, but to the list would
> be better. I'm looking to have to implement something similar myself right
> now, so if you've got some code that I can start with, I can run with it
> and see where it ends up :)

Sure, I don't mind, especially as my code is modified/extended from code I
pulled off this list. ;-)  I'll put the source at the end, feel free to use
it as you wish.  Just promise not to look at it in 80 columns!

Basically you can use moveTo() and moveBy() to scroll, blit()s and/or
clear()s followed by updateTexture() to change the image, and draw() does
just that.  Work these into your event loop, and you're set.

Hmmm, glancing over the code I see it's not immediately clear what
SurfaceTexture wants as a "sprite".  Anything with a .rect and .image as used
by it's pygame surface will do.

> And don't be worried about code quality (if you are :) ... remember that
> the best open source code is released early and released often!

In order for someone to meaningfully say my code sucks, they'd have to point
out why -- in which case I can improve my code. :-)

-Jasper


# This Module is modified from Bob Ippolito's code, found in pygame mail list archives

from OpenGL.GL     import *
from OpenGL.GLU    import *
from pygame.locals import *
import pygame

POWERS = (32, 64, 128, 256, 512, 1024, 2048, 4096)

def nextPower(x):
    for y in POWERS:
      if y >= x:
        return y

def surfaceToOglTexture( imgsurf, texture=glGenTextures(1), scale=0, mipmap=0 ):
    """Bind an image to opengl texture"""
    owidth, oheight = imgsurf.get_size()
    width, height   = tuple( map( nextPower,imgsurf.get_size() ) )
    imageStr        = pygame.image.tostring( imgsurf, "RGBA", 0 )

    glBindTexture( GL_TEXTURE_2D, texture )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR )

    if mipmap:
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR )
        gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, owidth, oheight, GL_RGBA, GL_UNSIGNED_BYTE, imageStr )
    else:
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
        if scale:
            image = gluScaleImage( GL_RGBA, owidth, oheight, imageStr, width, height, GL_UNSIGNED_BYTE )
            glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image )
        else:
            glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, None )
            glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, owidth, oheight, GL_RGBA, GL_UNSIGNED_BYTE, imageStr )

    return texture


def drawTexture( (x,y), (w,h), texture, (screenXRes,screenYRes) ):
    """Draw a Quad in Orthogonal mode with the specified texture"""
    pMatrix = glGetDoublev( GL_PROJECTION_MATRIX )
    mMatrix = glGetDoublev( GL_MODELVIEW_MATRIX )
    glMatrixMode( GL_PROJECTION )
    glLoadIdentity()
    gluOrtho2D( 0, screenXRes, screenYRes, 0 )

    glMatrixMode( GL_MODELVIEW )
    glLoadIdentity()
    glTranslatef( x, y, 0 )

    glEnable( GL_TEXTURE_2D )
    glBindTexture( GL_TEXTURE_2D, texture )

    glBegin( GL_QUADS )
    glTexCoord2f( 0.0, 0.0 ) ; glVertex2f( 0.0, 0.0 )
    glTexCoord2f( 0.0, 1.0 ) ; glVertex2f( 0.0, h )
    glTexCoord2f( 1.0, 1.0 ) ; glVertex2f( w,   h )
    glTexCoord2f( 1.0, 0.0 ) ; glVertex2f( w,   0.0 )
    glEnd()

    glDisable( GL_TEXTURE_2D )

    glMatrixMode( GL_PROJECTION )
    glLoadMatrixd( pMatrix )
    glMatrixMode( GL_MODELVIEW )
    glLoadMatrixd( mMatrix )


class SurfaceTexture:
    """A class for drawing and blitting 'sprites' to images as textures in OpenGL"""
    def __init__( self, surface, screenRes, size=None, pos=(0,0), scale=0, mipmap=0 ):
        self.surface   = surface.convert()
        self.texture   = surfaceToOglTexture( surface, scale=scale, mipmap=mipmap )
        self.screenRes = screenRes
        self.pos       = pos
        if size:
            self.size = size
        else:
            self.size = screenRes

        self.original   = surface.convert()
        self.dirtyRects = []

    def delete( self ):
        glDeleteTextures( [self.texture] )

    def moveTo( self, pos ):
        self.pos = pos

    def moveBy( self, pos ):
        self.pos = ( self.pos[0]+pos[0], self.pos[1]+pos[1] )

    def draw( self ):
        drawTexture( self.pos, self.size, self.texture, self.screenRes )

    def blit( self, sprites ):
        self.surface.lock()
        for sprite in sprites:
            self.surface.blit( sprite.image, sprite.rect )
        self.surface.unlock()
        self.dirtyRects.extend( [sprite.rect for sprite in sprites] )

    def clear( self, sprites ):
        self.surface.lock()
        for sprite in sprites:
            self.surface.blit( self.original.subsurface( sprite.rect ), sprite.rect )
        self.surface.unlock()
        self.dirtyRects.extend( [sprite.rect for sprite in sprites] )

    def updateTexture( self ):
        for rect in self.dirtyRects:
            subSurf  = self.surface.subsurface( rect )
            imageStr = pygame.image.tostring( subSurf, "RGBA", 0 )
            x,y,w,h  = rect

            glBindTexture( GL_TEXTURE_2D, self.texture )
            glTexSubImage2D( GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, imageStr )
        self.dirtyRects = []