左ドラッグで回転して、右ドラッグでドリーするところまで

だいぶ思い出してきた。
昨日作ったフォント表示を使ってみたが
Windowサイズを変更すると行間隔が変わってしまっていまいちなことが判明。
単純にglRasterPosで指定するだけではだめか。
なんか位置を固定する方策が必要だ。
あとglutだとマウスホイールが使えない様子。
たぶんファイルダイアログ機能とかもなさげ。
適当なところでツールキットを変える必要がありますな。
Qt(PyQt)とか使ってみたいのだが新しいGUIはじめると
横道にそれて帰って来れなくなりそうだ。

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

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from Image import *

# window idを記憶しておく
window=0

# mouse情報
lmb=GLUT_UP
mmb=GLUT_UP
rmb=GLUT_UP
last_x=0
last_y=0

# 視点情報
head=0.0
pitch=0.0
bank=0.0
distance=5.0

# フォント描画ディスプレイリストのオフセット
fontOffset=0

# 初期化とWindow生成
def createWindow(width, height, title):
  global window
  # initialize glut
  glutInit("")
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)

  # create window
  glutInitWindowSize(width, height)
  glutInitWindowPosition(100, 100)
  window = glutCreateWindow(title)

def initGL():
  glShadeModel(GL_SMOOTH)
  glEnable(GL_DEPTH_TEST)
  glEnable(GL_LIGHTING)
  glEnable(GL_LIGHT0)

  # メタセコ風味
  glClearColor(30.0/255.0, 65.0/255.0, 90.0/255.0, 1.0)

  # set callbacks
  glutDisplayFunc(display)
  glutReshapeFunc(reshape)
  glutKeyboardFunc(keyPressed)
  glutSpecialFunc(keyPressed)
  glutMouseFunc(mouse)
  glutMotionFunc(motion)

def makeRasterFontFromBitmap(file, letter_width, letter_height):
  global fontOffset
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

  # DisplayList
  fontOffset=glGenLists(128)

  # 画像からdisplayリストを作成
  bitmap = open("font.bmp")
  for code in range(128):
    x=(code % 16)*letter_width
    y=(code / 16)*letter_height
    letter=bitmap.crop([x, y, x+letter_width, y+letter_height]).transpose(FLIP_TOP_BOTTOM)

    glNewList(fontOffset+code, GL_COMPILE)
    glBitmap(letter_width, letter_height, 0.0, 0.0, letter_width, 0.0, letter.tostring())
    glEndList()

def printString(text, x, y):
  global fontOffset 
  glDisable(GL_LIGHTING)
  glMatrixMode(GL_PROJECTION)
  glPushMatrix()
  glLoadIdentity()

  glMatrixMode(GL_MODELVIEW)
  glPushMatrix()
  glLoadIdentity()

  # defulatでは(-1, -1)-(1, 1)の空間
  glColor(1.0, 0.0, 0.0)
  glRasterPos2f(x, y)
  glPushAttrib(GL_LIST_BIT)
  glListBase(fontOffset)
  glCallLists(text)
  glPopAttrib()

  glPopMatrix()
  glMatrixMode(GL_PROJECTION)
  glPopMatrix()
  glMatrixMode(GL_MODELVIEW)
  glEnable(GL_LIGHTING)

def resetPosition():
  global head, pitch, bank, display
  head=0
  pitch=0
  bank=0
  display=5

# 描画
def display():
  global head, pitch, bank, distance
  # バッファのクリア
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  # クリア
  glLoadIdentity()
  # 視点
  gluLookAt(0.0, 0.0, distance, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
  glRotate(head, 0, 1, 0)
  glRotate(pitch, 1, 0, 0)
  glRotate(bank, 0, 0, 1)
  # 描画
  glColor(1.0, 1.0, 1.0)
  glutSolidTeapot(1)
  # 文字
  printString("head : %f" % (head), -1, -0.4)
  printString("pitch: %f" % (pitch), -1, -0.6)
  printString("bank : %f" % (bank), -1, -0.8)
  printString("dist : %f" % (distance), -1, -1)
  # 実行
  glutSwapBuffers()

# ウィンドウリサイズ
def reshape(width, height):
  print 'reshape'
  if height==0:
    height=1
  glViewport(0, 0, width, height)
  glMatrixMode(GL_PROJECTION)
  glLoadIdentity()
  gluPerspective(30.0, float(width)/float(height), 1.0, 100.0);
  glMatrixMode(GL_MODELVIEW)

def keyPressed(key, x, y):
  global window
  if key== '\033' or key== "q":
    glutDestroyWindow(window)
    sys.exit()
  if key==GLUT_KEY_HOME:
    resetPosition()
    glutPostRedisplay()
  else:
    print key

# mouse button down & up
def mouse(button, state, x, y):
  global lmb, mmb, rmb, last_x, last_y
  if button==GLUT_LEFT_BUTTON:
    lmb=state
  elif button==GLUT_MIDDLE_BUTTON:
    mmb=state
  elif button==GLUT_RIGHT_BUTTON:
    rmb=state
  last_x=x
  last_y=y
  glutPostRedisplay()

# drag
def motion(x, y):
  global lmb, mmb, rmb, last_x, last_y, head, pitch, bank, distance
  #glutGetModifiers
  if lmb==GLUT_DOWN:
    # left head & pitch
    head+=x-last_x
    head=head % 360
    pitch+=y-last_y
    pitch=pitch % 360
  elif mmb==GLUT_DOWN:
    # middle pan
    None
  elif rmb==GLUT_DOWN:
    # right dolly
    None
    distance+=x-last_x
    distance+=0.5*(y-last_y)
    if distance<3.0:
      distance=3.0
  last_x=x
  last_y=y
  glutPostRedisplay()

def main():
  createWindow(150, 150, 'glut sample')
  initGL()
  makeRasterFontFromBitmap('font.bmp', 12, 12)
  glutMainLoop()

if __name__ == '__main__':
  print "Hit ESC key to quit."
  main()