""" Using pygame as a web interface builder. python pygame2web.py # runs the demo program in a pygame window python pygame2web.py 8000 # runs as a server for http://127.0.0.1:8000 """ import os, sys, re, time import pygame from pygame.locals import * import SimpleHTTPServer, htmlentitydefs from cStringIO import StringIO from py.magic import greenlet import process, pixmap, httpserver class BaseInterface: def pixmap(self, w, h, data, colorkey=-1, alpha=255): img = pygame.image.fromstring(data, (w, h), "RGB") if colorkey >= 0: r = colorkey & 0xFF g = (colorkey >> 8) & 0xFF b = (colorkey >> 16) & 0xFF img.set_colorkey([r, g, b], RLEACCEL) elif alpha >= 255: return img.convert(self.offscreen) if alpha < 255: img.set_alpha(alpha, RLEACCEL) return img def loadpixmap(self, filename, colorkey=-1, alpha=255): w, h, data = pixmap.decodepixmap(open(filename, 'rb')) return self.pixmap(w, h, data, colorkey, alpha) def putppm(self, x, y, bitmap): self.offscreen.blit(bitmap, (x, y)) # ____________________________________________________________ class PygameInterface(BaseInterface): def __init__(self, game): # Initialize pygame pygame.init() # Set the display mode winstyle = HWSURFACE # |FULLSCREEN bestdepth = pygame.display.mode_ok((game.width, game.height), winstyle, 32) self.screen = pygame.display.set_mode((game.width, game.height), winstyle, bestdepth) self.offscreen = pygame.Surface((game.width, game.height)) #decorate the game window pygame.display.set_caption(game.title) def flip(self): self.screen.blit(self.offscreen, (0, 0)) pygame.display.flip() def next_mouse_clic(self): self.flip() return greenlet.getcurrent().parent.switch() def mainloop(cls, game): intf = cls(game) g = greenlet(game.run) g.switch(intf) while 1: e = pygame.event.wait() if e.type == MOUSEBUTTONDOWN: g.switch(e.pos) elif e.type == QUIT: break mainloop = classmethod(mainloop) # ____________________________________________________________ class HttpInterface(BaseInterface): INDEXPAGE = ''' %(self.game.title)s ''' re_coords = re.compile(r"(\d+)[,](\d+)") TIMEOUT = 5 * 60 # never timeout before 5 minutes MAX_CLIENTS = 5 # timeout older clients if this is reached Clients = {} def __init__(self, game): # Initialize pygame pygame.init() self.offscreen = pygame.Surface((game.width, game.height)) self.game = game self.runner = greenlet(game.run) self.runner.switch(self) # let the game initialize itself def age(self): return time.time() - self.last_activity def indexpage(self, query='', **options): match = self.re_coords.match(query) if match: # invalidate the current state self.unregister() # send clics to the game x = int(match.group(1)) y = int(match.group(2)) self.runner.switch((x, y)) # validate the new state self.register() # build the html page f = httpserver.TranslatorIO(self.INDEXPAGE, locals()) return f, 'text/html' def currentimage(self, **options): width, height = self.offscreen.get_size() data = pygame.image.tostring(self.offscreen, "RGB") data = pixmap.encodepixmap(width, height, data) ppm = process.StringWriter(data) png = process.Process('pnmtopng', ppm) return png.as_file(), "image/png" def next_mouse_clic(self): return greenlet.getcurrent().parent.switch() # the answer is (x,y) sent by indexpage above def register(self): def randomid(): import random return str(random.randrange(0, sys.maxint)) stateid = randomid() while stateid in HttpInterface.Clients: stateid = randomid() HttpInterface.Clients[stateid] = self self.stateid = stateid self.last_activity = time.time() httpserver.register('%s/index.html' % self.stateid, self.indexpage) httpserver.register('%s/screen.png' % self.stateid, self.currentimage) def unregister(self): httpserver.unregister('%s/index.html' % self.stateid) httpserver.unregister('%s/screen.png' % self.stateid) del HttpInterface.Clients[self.stateid] def mainloop(cls, game): # class method. def mainindexpage(**options): clients = HttpInterface.Clients if len(clients) >= HttpInterface.MAX_CLIENTS: # throw off a client ages = [(c.age(), c) for c in clients.values()] age, c = max(ages) if age < HttpInterface.TIMEOUT: raise httpserver.HTTPRequestError( "too many clients, please try again later") c.unregister() # create a new client intf = cls(game) intf.register() return intf.indexpage() httpserver.register('', mainindexpage) httpserver.register('index.html', mainindexpage) httpserver.server_mainloop() mainloop = classmethod(mainloop) # ____________________________________________________________ if __name__ == '__main__': if len(sys.argv) == 1: Intf = PygameInterface else: Intf = HttpInterface class MyGame: width = 320 height = 200 title = "Hello!" def run(self, intf): "The complete demo program." FILE = 'demo.ppm' bmp = intf.loadpixmap(FILE, colorkey=0x010101) w, h = bmp.get_size() while 1: x, y = intf.next_mouse_clic() intf.putppm(x - w//2, y - h//2, bmp) Intf.mainloop(MyGame())