アニメーションを実装するのに独自のメインループを使いたいということで、glutからpygameに乗り換える。pygameはSDLのpython bindingです。
OpenGLを使うようにpygameを初期化して、メインループを開始するところまで。
#!/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)
三角形の描画
#!/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)
マウスに関する3つのイベント * pygame.MOUSEBUTTONDOWN * pygame.MOUSEBUTTONUP * pygame.MOUSEMOTION に反応するようにした。 MOUSEBUTTONDOWN, MOUSEBUTTONUPのbutton 4, 5でホイールの回転を取得できる。
#!/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)
キーボードイベントを拾ってESCまたはqで終了するようにした。
#!/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に変更する。
#!/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を分離する。 OpenGLは前の流用。
Note
pygameはゲーム向けなのでデフォルトではWindowのリサイズができないので、リサイズイベントも来ない。手動で最初に一度呼び出す。
#!/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)))
今まで作ったものを組み合わせて呼び出す。
#!/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))