Table Of Contents

Previous topic

Skinning

Next topic

BVH

This Page

pygameに移行

アニメーションを実装するのに独自のメインループを使いたいということで、glutからpygameに乗り換える。pygameはSDLのpython bindingです。

Create Window

OpenGLを使うようにpygameを初期化して、メインループを開始するところまで。

pgCreateWindow.py

#!/usr/bin/python
# coding: utf-8
import pygame
 

# 関数の出口に終了処理を追加するデコレータ
def cleanup(func):
    def wrap(*args):
        print('cleanup')
        func(*args)
        pygame.quit()
    return wrap


class PyGame:
    def __init__(self):
        self._running = True
        self._screen = None
 
    def initialize(self, w, h):
        pygame.init()
        # OPENGL向けに初期化する
        self._screen = pygame.display.set_mode(
            (w, h), pygame.OPENGL | pygame.DOUBLEBUF)

        if not self._screen:
            return

        return True
 
    def on_event(self, event):
        if event.type == pygame.QUIT:
            self._running = False

    def update(self):
        pass

    def draw(self):
        pass

    @cleanup
    def execute(self, w, h):
        if not self.initialize(w, h):
            return
 
        while self._running:
            for event in pygame.event.get():
                self.on_event(event)
            self.update()
            self.draw()
 

if __name__ == "__main__" :
    game=PyGame()
    game.execute(640, 480)

Draw Triangle

三角形の描画

pgDrawTriangle.py

#!/usr/bin/python
# coding: utf-8
import pygame
from OpenGL.GL import *


# 関数の出口に終了処理を追加するデコレータ
def cleanup(func):
    def wrap(*args):
        print('cleanup')
        func(*args)
        pygame.quit()
    return wrap


class PyGame:
    def __init__(self):
        self._running = True
        self._screen = None
 
    def initialize(self, w, h):
        pygame.init()
        # OPENGL向けに初期化する
        self._screen = pygame.display.set_mode(
            (w, h), pygame.OPENGL | pygame.DOUBLEBUF)

        if not self._screen:
            return

        return True
 
    def on_event(self, event):
        if event.type == pygame.QUIT:
            self._running = False

    def update(self):
        pass

    def draw(self):
        # OpenGLバッファのクリア
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 三角形描画開始
        glBegin(GL_TRIANGLES)
        # 左下
        glVertex(-1, -1)
        # 右下
        glVertex(1, -1)
        # 上
        glVertex(0, 1)
        # 三角形描画終了
        glEnd()
        # OpenGL描画実行
        glFlush()

        # pygameダブルバッファ交換
        pygame.display.flip()

    @cleanup
    def execute(self, w, h):
        if not self.initialize(w, h):
            return
 
        while self._running:
            for event in pygame.event.get():
                self.on_event(event)
            self.update()
            self.draw()
 

if __name__ == "__main__" :
    game=PyGame()
    game.execute(640, 480)

Mouseイベント

マウスに関する3つのイベント * pygame.MOUSEBUTTONDOWN * pygame.MOUSEBUTTONUP * pygame.MOUSEMOTION に反応するようにした。 MOUSEBUTTONDOWN, MOUSEBUTTONUPのbutton 4, 5でホイールの回転を取得できる。

pgMouse.py

#!/usr/bin/python
# coding: utf-8
import pygame
from OpenGL.GL import *


# 関数の出口に終了処理を追加するデコレータ
def cleanup(func):
    def wrap(*args):
        print('cleanup')
        func(*args)
        pygame.quit()
    return wrap


class PyGame:
    def __init__(self):
        self._running = True
        self._screen = None

        # eventの分岐をディクショナリに変更
        self._eventMap={
                pygame.QUIT: self.onQuit,
                pygame.MOUSEBUTTONDOWN: self.onMouseDown,
                pygame.MOUSEBUTTONUP: self.onMouseUp,
                pygame.MOUSEMOTION: self.onMouseMotion,
                }
 
    def initialize(self, w, h):
        pygame.init()
        # OPENGL向けに初期化する
        self._screen = pygame.display.set_mode(
            (w, h), pygame.OPENGL | pygame.DOUBLEBUF)

        if not self._screen:
            return

        return True
 
    def on_event(self, event):
        if event.type in self._eventMap:
            self._eventMap[event.type](event)

    def onQuit(self, event):
        self._running = False

    def onMouseDown(self, event):
        if event.button==1:
            print('onMouseDown', 'left', event.pos)
        elif event.button==2:
            print('onMouseDown', 'middle', event.pos)
        elif event.button==3:
            print('onMouseDown', 'right', event.pos)
        elif event.button==4:
            print('onMouseDown', 'wheelup', event.pos)
        elif event.button==5:
            print('onMouseDown', 'wheeldown', event.pos)

    def onMouseUp(self, event):
        if event.button==1:
            print('onMouseDown', 'left', event.pos)
        elif event.button==2:
            print('onMouseDown', 'middle', event.pos)
        elif event.button==3:
            print('onMouseDown', 'right', event.pos)
        elif event.button==4:
            print('onMouseDown', 'wheelup', event.pos)
        elif event.button==5:
            print('onMouseDown', 'wheeldown', event.pos)

    def onMouseMotion(self, event):
        print('onMouseMotion', event.pos, event.rel, event.buttons)

    def update(self):
        pass

    def draw(self):
        # OpenGLバッファのクリア
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 三角形描画開始
        glBegin(GL_TRIANGLES)
        # 左下
        glVertex(-1, -1)
        # 右下
        glVertex(1, -1)
        # 上
        glVertex(0, 1)
        # 三角形描画終了
        glEnd()
        # OpenGL描画実行
        glFlush()

        # pygameダブルバッファ交換
        pygame.display.flip()

    @cleanup
    def execute(self, w, h):
        if not self.initialize(w, h):
            return
 
        while self._running:
            for event in pygame.event.get():
                self.on_event(event)
            self.update()
            self.draw()
 

if __name__ == "__main__" :
    game=PyGame()
    game.execute(640, 480)

Keyboardイベント

キーボードイベントを拾ってESCまたはqで終了するようにした。

pgKeyboard.py

#!/usr/bin/python
# coding: utf-8
import pygame
from OpenGL.GL import *


# 関数の出口に終了処理を追加するデコレータ
def cleanup(func):
    def wrap(*args):
        print('cleanup')
        func(*args)
        pygame.quit()
    return wrap


class PyGame:
    def __init__(self):
        self._running = True
        self._screen = None

        # eventの分岐をディクショナリに変更
        self._eventMap={
                pygame.QUIT: self.onQuit,
                pygame.MOUSEBUTTONDOWN: self.onMouseDown,
                pygame.MOUSEBUTTONUP: self.onMouseUp,
                pygame.MOUSEMOTION: self.onMouseMotion,
                pygame.KEYDOWN: self.onKeyDown,
                pygame.KEYUP: self.onKeyUp,
                }
 
    def initialize(self, w, h):
        pygame.init()
        # OPENGL向けに初期化する
        self._screen = pygame.display.set_mode(
            (w, h), pygame.OPENGL | pygame.DOUBLEBUF)

        if not self._screen:
            return

        return True
 
    def on_event(self, event):
        if event.type in self._eventMap:
            self._eventMap[event.type](event)

    def onQuit(self, event):
        self._running = False

    def onMouseDown(self, event):
        if event.button==1:
            print('onMouseDown', 'left', event.pos)
        elif event.button==2:
            print('onMouseDown', 'middle', event.pos)
        elif event.button==3:
            print('onMouseDown', 'right', event.pos)
        elif event.button==4:
            print('onMouseDown', 'wheelup', event.pos)
        elif event.button==5:
            print('onMouseDown', 'wheeldown', event.pos)

    def onMouseUp(self, event):
        if event.button==1:
            print('onMouseDown', 'left', event.pos)
        elif event.button==2:
            print('onMouseDown', 'middle', event.pos)
        elif event.button==3:
            print('onMouseDown', 'right', event.pos)
        elif event.button==4:
            print('onMouseDown', 'wheelup', event.pos)
        elif event.button==5:
            print('onMouseDown', 'wheeldown', event.pos)

    def onMouseMotion(self, event):
        print('onMouseMotion', event.pos, event.rel, event.buttons)

    def onKeyDown(self, event):
        if event.key==27: # ESCAPE
            pygame.event.post(pygame.event.Event(pygame.QUIT))
        elif event.unicode==u'q':
            pygame.event.post(pygame.event.Event(pygame.QUIT))
        else:
            print(event.unicode, event.key, event.mod)

    def onKeyUp(self, event):
        print(event.key, event.mod)

    def update(self):
        pass

    def draw(self):
        # OpenGLバッファのクリア
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 三角形描画開始
        glBegin(GL_TRIANGLES)
        # 左下
        glVertex(-1, -1)
        # 右下
        glVertex(1, -1)
        # 上
        glVertex(0, 1)
        # 三角形描画終了
        glEnd()
        # OpenGL描画実行
        glFlush()

        # pygameダブルバッファ交換
        pygame.display.flip()

    @cleanup
    def execute(self, w, h):
        if not self.initialize(w, h):
            return
 
        while self._running:
            for event in pygame.event.get():
                self.on_event(event)
            self.update()
            self.draw()
 

if __name__ == "__main__" :
    game=PyGame()
    game.execute(640, 480)

固定FPSの導入

ウェイト無しでループが回っているので、これを固定FPSに変更する。

pgFPS.py

#!/usr/bin/python
# coding: utf-8
import pygame
from OpenGL.GL import *

import fpstimer


# 関数の出口に終了処理を追加するデコレータ
def cleanup(func):
    def wrap(*args):
        print('cleanup')
        func(*args)
        pygame.quit()
    return wrap


class PyGame:
    def __init__(self):
        self._running = True
        self._screen = None

        # eventの分岐をディクショナリに変更
        self._eventMap={
                pygame.QUIT: self.onQuit,
                pygame.MOUSEBUTTONDOWN: self.onMouseDown,
                pygame.MOUSEBUTTONUP: self.onMouseUp,
                pygame.MOUSEMOTION: self.onMouseMotion,
                pygame.KEYDOWN: self.onKeyDown,
                pygame.KEYUP: self.onKeyUp,
                }
 
    def initialize(self, w, h):
        pygame.init()
        # OPENGL向けに初期化する
        self._screen = pygame.display.set_mode(
            (w, h), pygame.OPENGL | pygame.DOUBLEBUF)

        if not self._screen:
            return

        return True
 
    def on_event(self, event):
        if event.type in self._eventMap:
            self._eventMap[event.type](event)

    def onQuit(self, event):
        self._running = False

    def onMouseDown(self, event):
        if event.button==1:
            print('onMouseDown', 'left', event.pos)
        elif event.button==2:
            print('onMouseDown', 'middle', event.pos)
        elif event.button==3:
            print('onMouseDown', 'right', event.pos)
        elif event.button==4:
            print('onMouseDown', 'wheelup', event.pos)
        elif event.button==5:
            print('onMouseDown', 'wheeldown', event.pos)

    def onMouseUp(self, event):
        if event.button==1:
            print('onMouseDown', 'left', event.pos)
        elif event.button==2:
            print('onMouseDown', 'middle', event.pos)
        elif event.button==3:
            print('onMouseDown', 'right', event.pos)
        elif event.button==4:
            print('onMouseDown', 'wheelup', event.pos)
        elif event.button==5:
            print('onMouseDown', 'wheeldown', event.pos)

    def onMouseMotion(self, event):
        print('onMouseMotion', event.pos, event.rel, event.buttons)

    def onKeyDown(self, event):
        if event.key==27: # ESCAPE
            pygame.event.post(pygame.event.Event(pygame.QUIT))
        elif event.unicode==u'q':
            pygame.event.post(pygame.event.Event(pygame.QUIT))
        else:
            print(event.unicode, event.key, event.mod)

    def onKeyUp(self, event):
        print(event.key, event.mod)

    def update(self, elasp):
        pass

    def draw(self):
        # OpenGLバッファのクリア
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 三角形描画開始
        glBegin(GL_TRIANGLES)
        # 左下
        glVertex(-1, -1)
        # 右下
        glVertex(1, -1)
        # 上
        glVertex(0, 1)
        # 三角形描画終了
        glEnd()
        # OpenGL描画実行
        glFlush()

        # pygameダブルバッファ交換
        pygame.display.flip()

    @cleanup
    def execute(self, w, h):
        if not self.initialize(w, h):
            return
 
        fps=fpstimer.FPSTimer(60)
        frameCount=0
        while self._running:
            for event in pygame.event.get():
                self.on_event(event)

            elasp=fps.update()
            self.update(elasp)
            fps.waitFrame()
            self.draw()

            frameCount+=1
            if frameCount % 120==0:
                pygame.display.set_caption("%d fps" % fps.getFps())
            

if __name__ == "__main__" :
    game=PyGame()
    game.execute(640, 480)

pygameとOpenGLの分離

pygameとOpenGLを分離する。 OpenGLは前の流用。

Note

pygameはゲーム向けなのでデフォルトではWindowのリサイズができないので、リサイズイベントも来ない。手動で最初に一度呼び出す。

pg_ui.py

#!/usr/bin/python
# coding: utf-8
import pygame
from OpenGL.GL import *

# OpenGL制御の読み込み
import glbase
import fpstimer

# 関数の出口に終了処理を追加するデコレータ
def cleanup(func):
    def wrap(*args):
        #print('cleanup')
        func(*args)
        pygame.quit()
    return wrap


class PyGame(object):
    def __init__(self, engine):
        self._running = True
        self._screen = None
        # OpenGL処理用の変数
        self.engine=engine

        # eventの分岐をディクショナリに変更
        self._eventMap={
                pygame.QUIT: self.onQuit,
                pygame.MOUSEBUTTONDOWN: self.onMouseDown,
                pygame.MOUSEBUTTONUP: self.onMouseUp,
                pygame.MOUSEMOTION: self.onMouseMotion,
                pygame.KEYDOWN: self.onKeyDown,
                pygame.KEYUP: self.onKeyUp,
                pygame.VIDEORESIZE: self.onResize,
                }
 
    def initialize(self, w, h):
        pygame.init()
        # OPENGL向けに初期化する
        self._screen = pygame.display.set_mode(
            (w, h), pygame.OPENGL | pygame.DOUBLEBUF)

        if not self._screen:
            return

        # サイズ指定
        self.engine.onResize(w, h)

        return True
 
    def on_event(self, event):
        if event.type in self._eventMap:
            self._eventMap[event.type](event)

    def onQuit(self, event):
        self._running = False

    def onResize(self, event):
        print(onResize)
        self.engine.onResize(event.w, event.h)

    def onMouseDown(self, event):
        if event.button==1:
            self.engine.onLeftDown(*event.pos)
        elif event.button==2:
            self.engine.onMiddleDown(*event.pos)
        elif event.button==3:
            self.engine.onRightDown(*event.pos)
        elif event.button==4:
            self.engine.onWheel(-1)
        elif event.button==5:
            self.engine.onWheel(1)

    def onMouseUp(self, event):
        if event.button==1:
            self.engine.onLeftUp(*event.pos)
        elif event.button==2:
            self.engine.onMiddleUp(*event.pos)
        elif event.button==3:
            self.engine.onRightUp(*event.pos)

    def onMouseMotion(self, event):
        self.engine.onMotion(*event.pos)

    def onKeyDown(self, event):
        if event.key==27: # ESCAPE
            print("exit...")
            pygame.event.post(pygame.event.Event(pygame.QUIT))
            return
        elif event.unicode==u'q':
            print("exit...")
            pygame.event.post(pygame.event.Event(pygame.QUIT))
            return
        else:
            print(event.unicode, event.key, event.mod)
            self.engine.onKeyDown(event.unicode.encode('utf-8'))

    def onKeyUp(self, event):
        print(event.key, event.mod)

    def update(self, interval):
        self.engine.onUpdate(interval)

    def draw(self):
        self.engine.draw()
        # pygameダブルバッファ交換
        pygame.display.flip()

    @cleanup
    def execute(self, w, h):
        if not self.initialize(w, h):
            return

        fps=fpstimer.FPSTimer(60)
        frameCount=0
        while self._running:
            for event in pygame.event.get():
                self.on_event(event)
            interval=fps.update()
            self.update(interval)
            fps.waitFrame()
            self.draw()

            frameCount+=1
            if frameCount % 120==0:
                pygame.display.set_caption("%d fps" % fps.getFps())
            
 

def run(engine):
    game=PyGame(engine)
    game.execute(640, 480)

if __name__=="__main__":
    import Rokuro
    import triangle
    run(glbase.BaseController(Rokuro.RokuroView(100), triangle.Triangle(30)))

分離したuiにmqoビューワを乗せてみる

今まで作ったものを組み合わせて呼び出す。

pgMQO.py

#!/usr/bin/python
# coding: utf-8

import sys
import time

import pg_ui
import builder4
import glbase
import Rokuro
import mqo

if __name__=="__main__":
    if len(sys.argv)<2:
        print "usage: %s {mqo file}" % sys.argv[0]
        sys.exit()
    # load scenee
    t=time.time()
    l=mqo.Loader()
    if not l.load(sys.argv[1]):
        sys.exit()
    print time.time()-t, "sec"
    # build
    print l
    view=Rokuro.RokuroView(400)
    root=builder4.build(l)
    pg_ui.run(glbase.BaseController(view, root))
inserted by FC2 system