結局wxPython
glutではちと機能不足になってきたのでXとWindows両方で動くpython GUIを選定していたのだが、
TkinterのOpenGLを使うのに失敗した(ToglをWindowsにインストールするのが難航しそうだった)のと、
GentooでQtのコンパイルが一向に終わらないため使ったことのあるwxPythonに決めた。
wxPythonではwx.glcanvas.GLCanvasを使う。
glutDisplayFuncとかglutReshapeFuncとかはwxPythonの流儀でBindとかを使う。
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBG)で何もしない関数を登録しておかないとOpenGLとWxWidgetsで2重にクリアするためかちらつくのに注意。
# -*- coding: utf-8 -*- import wx import wx.glcanvas from OpenGL.GLUT import * from OpenGL.GLU import * from OpenGL.GL import * class Camera(object): """視点 """ __slots__=['pos', 'target', 'up'] def __init__(self, pos, target, up, aspect=1): self.pos=pos self.target=target self.up=up class Projection(object): """投影情報 """ __slots__=['fovy', 'near', 'far', 'aspect'] def __init__(self, fovy, near, far): self.fovy=fovy self.near=near self.far=far self.aspect=1 class MyGLCanvas(wx.glcanvas.GLCanvas): def __init__(self, *args, **keys): attribList = (wx.glcanvas.WX_GL_RGBA, # RGBA wx.glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered wx.glcanvas.WX_GL_DEPTH_SIZE, 32) # 32 bit super(MyGLCanvas, self).__init__(attribList=attribList, *args, **keys) # コールバック self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnResize) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBG) # camera self.camera=Camera((0, 0, 10), (0, 0, 0), (0, 1, 0)) # 投影 self.projection=Projection(30.0, 0.1, 20) # 初期化フラグ self.initialized=0 def InitGL(self): """初期化。GLCanvasの実体が作成された後でコールすべし? """ # 光源 glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) # 隠面消去を有効に glEnable(GL_DEPTH_TEST) # 法線の自動正規化 glEnable(GL_NORMALIZE) # 背景色 glClearColor(0.09375, 0.2578125, 0.3515625, 1.0); # デップスバッファ glClearDepth(1.0) # 初期化フラグ self.initialized = 1 def Draw(self): """ OpenGLの描画 """ # クリア glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 行列の初期化 glMatrixMode(GL_MODELVIEW) glLoadIdentity() # 視点 gluLookAt( self.camera.pos[0], self.camera.pos[1], self.camera.pos[2], self.camera.target[0], self.camera.target[1], self.camera.target[2], self.camera.up[0], self.camera.up[1], self.camera.up[2] ) # ティーポット glutSolidTeapot( 2 ) # 描画 self.SwapBuffers() def OnPaint(self, event): """画面更新 """ dc = wx.PaintDC(self) self.SetCurrent() if not self.initialized: self.InitGL() self.Draw() event.Skip() return def OnResize(self, event): """ Windowのサイズ変更 """ size = self.size = self.GetClientSize() if self.GetContext(): self.SetCurrent() glViewport(0, 0, self.size.width, self.size.height) if self.size.height!=0: self.projection.aspect=float(self.size.width)/float(self.size.height) # 透視投影 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective( self.projection.fovy, self.projection.aspect, self.projection.near, self.projection.far) self.Refresh() event.Skip() def OnEraseBG(self, event): """Process the erase background event. """ pass # Do nothing, to avoid flashing on MSWin class MyFrame(wx.Frame): def __init__(self, parent): super(MyFrame, self).__init__(parent) panel=MyGLCanvas(self) sizer=wx.BoxSizer(wx.HORIZONTAL) self.SetSizer(sizer) sizer.Add(panel, 1, wx.EXPAND) if __name__ == '__main__': app = wx.PySimpleApp() frame = MyFrame(None) frame.Show() app.MainLoop()