Table Of Contents

Previous topic

Basics

Next topic

Model View Matrix

This Page

Framework

ソースコードのリファクタリング。 ウィンドウシステムを制御するglut部分と、OpenGLそのものに関する部分に分離する。

glutインターフェース

glutが受け取ったマウスイベント、キーボードイベント、ウィンドウリサイズイベント、描画要求をOpenGL管理クラスに丸投げする。 ダブルバッファの入れ替えもglutの仕事となる。

glut_ui.py

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

from OpenGL.GLUT import *

# このソースではOpenGL操作をしない
#from OpenGL.GL import *

# OpenGL処理用のglobal変数
# glutのコールバック関数に来たイベントをここに丸投げする
g_engine=None


def resize(w, h):
    global g_engine
    g_engine.onResize(w, h)


def mouse(button, state, x, y):
    global g_engine

    # マウスイベントの振り分けはここでしてしまう
    # g_engineのメソッドからTrueが返ったら再描画する
    if button==GLUT_LEFT_BUTTON:
        if state==GLUT_DOWN:
            if g_engine.onLeftDown(x, y):
                glutPostRedisplay()
        else:
            if g_engine.onLeftUp(x, y):
                glutPostRedisplay()
    elif button==GLUT_MIDDLE_BUTTON:
        if state==GLUT_DOWN:
            if g_engine.onMiddleDown(x, y):
                glutPostRedisplay()
        else:
            if g_engine.onMiddleUp(x, y):
                glutPostRedisplay()
    elif button==GLUT_RIGHT_BUTTON:
        if state==GLUT_DOWN:
            if g_engine.onRightDown(x, y):
                glutPostRedisplay()
        else:
            if g_engine.onRightUp(x, y):
                glutPostRedisplay()

    elif button==3:
        if g_engine.onWheel(-1):
            glutPostRedisplay()

    elif button==4:
        if g_engine.onWheel(1):
            glutPostRedisplay()

    else:
        print "unknown mouse:", button, state, x, y


def motion(x, y):
    global g_engine
    if g_engine.onMotion(x, y):
        glutPostRedisplay()


def keyboard(key, x, y):
    if key=='\033':
        # Escape
        sys.exit()
    if key=='q':
        # q
        sys.exit()
    else:
        print(key)


def draw():
    global g_engine
    g_engine.draw()
    glutSwapBuffers()


def run(engine):
    global g_engine
    g_engine=engine

    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
    glutInitWindowSize(640, 480)
    glutCreateWindow("glut sample")
    # Windowのサイズが変わった時に呼ばれる関数を登録
    glutReshapeFunc(resize)
    # 描画時に呼ばれる関数を登録
    glutDisplayFunc(draw)
    # マウスボタン押し上げ時に呼ばれる関数
    glutMouseFunc(mouse)
    # マウスドラッグ時に呼ばれる関数
    glutMotionFunc(motion)
    # キーボードが押された時に呼ばれる関数
    glutKeyboardFunc(keyboard)

    glutMainLoop()

OpenGL管理クラス

GUI(glut)からマウスイベント、キーボードイベント、ウィンドウリサイズイベントを受け付ける。また、drawで画面のクリアとバックバッファの更新(glFlush)行う。 Viewクラスにマウスイベントを委譲する。

glbase.py

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

from OpenGL.GL import *
import re

DELEGATE_PATTERN=re.compile('^on[A-Z]')

class BaseController(object):
    def __init__(self, view, root):
        self.view=view
        self.root=root
        self.isInitialized=False
        self.delegate(view)
        self.delegate(root)

    def delegate(self, to):
        for name in dir(to):  
            if DELEGATE_PATTERN.match(name):
                method = getattr(to, name)  
                setattr(self, name, method)

    def onUpdate(*args):pass
    def onLeftDown(*args):pass
    def onLeftUp(*args):pass
    def onMiddleDown(*args):pass
    def onMiddleUp(*args):pass
    def onRightDown(*args):pass
    def onRightUp(*args):pass
    def onMotion(*args):pass
    def onResize(*args):pass
    def onWheel(*args):pass
    def onKeyDown(*args):pass
    def onInitialize(*args):pass

    def initilaize(self):
        self.view.onResize()
        glEnable(GL_DEPTH_TEST)
        # 初期化時の呼び出し
        self.onInitialize()

    def draw(self):
        if not self.isInitialized:
            self.initilaize()
            self.isInitialized=True
        # OpenGLバッファのクリア
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 投影行列のクリア
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        self.view.updateProjection()
        # モデルビュー行列のクリア
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        # OpenGL描画
        self.view.updateView()
        self.root.draw()
        glFlush()

Viewクラス

描画時のビューの操作と、マウスイベントの受付

baseview.py

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

from OpenGL.GL import *


class BaseView(object):
    def __init__(self):
        self.x=0
        self.y=0
        self.w=1
        self.h=1
        self.isLeftDown=False
        self.isMiddelDown=False
        self.isRightDown=False

    def updateProjection(self):
        pass

    def updateView(self):
        pass

    def onResize(self, w=None, h=None):
        self.w=w or self.w
        self.h=h or self.h
        glViewport(0, 0, self.w, self.h)

    def onLeftDown(self, x, y):
        self.isLeftDown=True
        self.x=x
        self.y=y

    def onLeftUp(self, x, y):
        self.isLeftDown=False

    def onMiddleDown(self, x, y):
        self.isMiddelDown=True
        self.x=x
        self.y=y

    def onMiddleUp(self, x, y):
        self.isMiddelDown=False

    def onRightDown(self, x, y):
        self.isRightDown=True
        self.x=x
        self.y=y

    def onRightUp(self, x, y):
        self.isRightDown=False

    def onMotion(self, x, y):
        print "onMotion", x, y

    def printMatrix(self, m):
        print(m[0][0], m[0][1], m[0][2], m[0][3])
        print(m[1][0], m[1][1], m[1][2], m[1][3])
        print(m[2][0], m[2][1], m[2][2], m[2][3])
        print(m[3][0], m[3][1], m[3][2], m[3][3])

使い方

sample.py

#!/usr/bin/python
# coding: utf8

from OpenGL.GL import *

import glut_ui
import glbase
import baseview
import triangle

if __name__=="__main__":
    glut_ui.run(glbase.BaseController(
        baseview.BaseView(), 
        triangle.Triangle(0.5)))
inserted by FC2 system