Skip to content

Instantly share code, notes, and snippets.

@mieki256
Last active April 10, 2024 01:31
Show Gist options
  • Save mieki256/f6e680b5cfafdb2f099e5fd51f66c708 to your computer and use it in GitHub Desktop.
Save mieki256/f6e680b5cfafdb2f099e5fd51f66c708 to your computer and use it in GitHub Desktop.
PyGame+PyOpenGLのサンプル。Windows7 x64 + Python 2.7.8 32bit + PyGame 1.9.2a0 + PyOpenGL で動作確認した。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"""
PyGame + OpenGLのテストサンプル
- Pキー : 平行投影/透視投影の切り替え
- Wキー : ワイヤーフレーム/ソリッド表示の切り替え
- Lキー : 照明のon/off
- Tキー : テクスチャ設定の切り替え(3種類)
- Sキー : ポイントスプライトの切り替え
- Fキー : ウインドウ/フルスクリーン切り替え
- カーソルキー : ティーポットの回転
- Bキー : Pause
- ESCキー,Qキー : 終了
- マウスカーソルの位置に合わせて図形の表示位置を変える。
参考ページ:
pygameに移行 ? メモ庫 v1.0 documentation
http://gunload.web.fc2.com/opengl/tutorial/skinning/pygame/
PyOpenGL + PIL でテクスチャ貼り - 銀月の符号
http://d.hatena.ne.jp/fgshun/20080922/1222095288
Wiki - pygame - python game development
http://www.pygame.org/wiki/SimpleOpenGL2dClasses
"""
import pygame
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL.extensions import alternate
from OpenGL.GL.ARB.point_parameters import *
from OpenGL.GL.EXT.point_parameters import *
import math
# 照明
light_ambient = [1.0, 1.0, 1.0, 1.0] # 環境光(白色)
light_diffuse = [1.0, 1.0, 1.0, 1.0] # 拡散光(白色)
light_specular = [1.0, 1.0, 1.0, 1.0] # 鏡面光(白色)
light_position = [2.0, 2.0, 1.0, 1.0] # 照明の位置
# マテリアル
no_mat = [0.0, 0.0, 0.0, 1.0] # 反射しない
mat_ambient = [0.0, 0.0, 0.3, 1.0] # 環境光の青成分だけ少し反射
mat_diffuse = [0.0, 1.0, 0.0, 1.0] # 拡散光の緑成分を全反射
mat_specular = [1.0, 1.0, 1.0, 1.0] # 鏡面光の全成分を全反射
mat_emission = [0.3, 0.3, 0.2, 0.0] # 放射の色
no_shininess = [0.0] # 鏡面反射しない
low_shininess = [5.0] # 弱い鏡面反射
high_shininess = [100.0] # 強い鏡面反射
glPointParameterf = alternate(
glPointParameterf, glPointParameterfARB, glPointParameterfEXT
)
glPointParameterfv = alternate(
glPointParameterfv, glPointParameterfvARB, glPointParameterfEXT
)
RESET_ATTENUATION = [1.0, 1.0, 1.0]
class PyGame:
def __init__(self):
"""コンストラクタ"""
self._running = True
self._screen = None
self.frame = 0 # フレームカウンタ
self.mx = 0
self.my = 0
self.tex = []
self.cap = ""
self.pausefg = False
# キー操作で変更するフラグ群
self.flag2d = True # 平行/透視投影
self.wireframe = False # ワイヤーフレーム/ソリッド表示
self.light_enable = True # 照明 on/off
self.tex_mode = 0 # テクスチャモード
self.point_spr = False # ポイントスプライト on/ff
self.fullscr = False # フルスクリーン/ウインドウ表示
self.filter_type = 0 # テクスチャのフィルタ種類(0 or 1)
self.tex_repeat = False # テクスチャをリピートさせるか否か
self.line_width = 1.0 # ワイヤーフレーム表示時の線の太さ
# 画面の縦横幅記録用
self.view_wh = 1.0
self.view_hh = 1.0
# テクスチャ付きポリゴンの色指定用
self.texcol = 0.0
self.texcol_spd = 0.01
self.angle = 0.0 # 回転角度
self.scale = 0.0 # 拡大縮小
self.xrot = 0.0 # 回転角度
self.yrot = 0.0
self.xspeed = 0.0 # 回転速度
self.yspeed = 0.0
self.mvfrm = 0
# 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() # PyGame初期化
self.scrw = float(w)
self.scrh = float(h)
glutInit(sys.argv)
return self.init_gl()
def init_gl(self):
"""OpenGL関係の初期化"""
w = int(self.scrw)
h = int(self.scrh)
# OPENGL向けに初期化する
modev = pygame.OPENGL | pygame.DOUBLEBUF
if self.fullscr:
modev |= pygame.FULLSCREEN
self._screen = pygame.display.set_mode((w, h), modev)
if not self._screen:
return False
glViewport(0, 0, int(self.scrw), int(self.scrh))
glClearColor(0.0, 0.0, 0.5, 1.0) # クリア色の設定
# 隠面消去、カリングを設定
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK) # 裏面をカリング
# 照明の設定
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient)
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse)
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular)
glLightfv(GL_LIGHT0, GL_POSITION, light_position)
glEnable(GL_LIGHTING) # 照明を有効化
glEnable(GL_LIGHT0) # 0番目の照明を有効化
# テクスチャの読み込み
glEnable(GL_TEXTURE_2D) # テクスチャ有効化
t = self.loadImage('res/tex1.png')
self.tex.append(t[0])
t = self.loadImage('res/tex2.png')
self.tex.append(t[0])
t = self.loadImage('res/tex4.png')
self.tex.append(t[0])
# ウインドウ内の座標値を計算して記録
# (-w ~ 0.0 ~ +w, +h ~ 0.0 ~ -h)
s = 8.0
self.view_wh = s * (self.scrw / self.scrh)
self.view_hh = s
if self.flag2d:
self.set_view2d()
else:
self.set_view3d()
return True
def loadImage(self, image_fila_path):
"""テクスチャ画像をロード"""
# PyGameを使って画像ロード
textureSurface = pygame.image.load(image_fila_path) # 画像読み込み
width = textureSurface.get_width() # 横幅取得
height = textureSurface.get_height() # 縦幅取得
# OpenGLに渡すために文字列化
textureData = pygame.image.tostring(textureSurface, "RGBA", False)
texture = glGenTextures(1) # テクスチャを1枚生成
glBindTexture(GL_TEXTURE_2D, texture) # テクスチャとして登録
# _S は横方向、_T は縦方向
# テクスチャをリピートさせるかしないか
if self.tex_repeat:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
else:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
# _MAG_FILTER は拡大時のフィルタ種類, _MIN_ は縮小?
if self.filter_type == 0:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
else:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
# glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
# glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
# ポイントスプライトにも使えるように設定
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)
# テクスチャを設定
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, textureData)
# アルファテストの判別関数
# コレを入れないとポイントスプライトを透過できない
glAlphaFunc(GL_GREATER, 0.5)
return texture, width, height
def set_view2d(self):
"""2D描画用に設定"""
# 座標系の設定
glMatrixMode(GL_PROJECTION) # 射影変換
glLoadIdentity() # 単位行列
# 以後、平行投影で描画するよう指定
glOrtho(-self.view_wh, self.view_wh,
- self.view_hh, self.view_hh, 0.1, 100.0)
# 以下のように書けば、2Dっぽい座標系になる
# gluOrtho2D(0, 640, 480, 0)
def set_view3d(self):
"""3D描画用に設定"""
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# 以後、透視投影で描画するよう指定
gluPerspective(60.0, self.scrw / self.scrh, 0.1, 100.0)
def set_tex_mode(self):
"""テクスチャモードの切り替え"""
md = [
GL_REPLACE,
GL_MODULATE,
GL_DECAL
]
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, md[self.tex_mode])
def update(self):
"""毎フレーム呼ばれる処理"""
if not self.pausefg:
# マウス座標を表示系の座標値に変換して記録
wh = self.scrw / 2.0
hh = self.scrh / 2.0
self.tx = (self.mx - wh) / wh
self.ty = (self.scrh - self.my - hh) / hh
self.tx *= self.view_wh
self.ty *= self.view_hh
self.angle += 1.5 # 角度を更新
self.scale = 2.0 * math.cos(math.radians(self.mvfrm)) + 2.5
self.xrot += self.xspeed
self.yrot += self.yspeed
# オブジェクトの色指定用変数を変更
self.texcol += self.texcol_spd
if self.texcol >= 1.0 or self.texcol <= 0.0:
self.texcol_spd *= -1
self.mvfrm += 1
def draw(self):
"""描画処理"""
# OpenGLバッファのクリア
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# 視野変換:カメラの位置と方向のセット
# gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
# glShadeModel(GL_FLAT) # フラットシェーディングを有効化
glShadeModel(GL_SMOOTH) # スムースシェーディングを有効化
glEnable(GL_NORMALIZE) # 法線の自動正規化を有効化
# 平行投影/透視投影を設定
if self.flag2d:
self.set_view2d()
else:
self.set_view3d()
# 照明の有効/無効化
if self.light_enable:
glEnable(GL_LIGHTING)
else:
glDisable(GL_LIGHTING)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
self.draw_teapot() # ティーポットを描画
self.draw_ball() # 球を描画
self.draw_cube() # 箱を描画
glDisable(GL_LIGHTING) # 照明無効化
self.draw_point(-self.angle / 4.0, self.view_hh * 0.5) # 点を描画
x = self.tx
y = self.ty
w = self.view_wh
h = self.view_hh
# テクスチャ付きポリゴンを描画(テクスチャ1)
tx = 0.0
ty = 0.0
tz = -60.0
texid = 0
self.draw_polygon_tex(tx, ty, tz, 1.0, 1.0, h, h, texid)
# テクスチャ付きポリゴンを描画(テクスチャ2)
tx = self.view_wh / 3
tz = -40.0
texid = 1
self.draw_polygon_tex(tx, ty, tz, 1.0, 1.0, h, h, texid)
self.set_view2d() # 平行投影にするよう設定
glDisable(GL_DEPTH_TEST) # 隠面消去を無効
glDisable(GL_CULL_FACE) # カリング無効化
glClear(GL_DEPTH_BUFFER_BIT) # デプスバッファクリア
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
self.draw_box(x, y, w, h) # 赤いグラデの四角形を描画
self.draw_tri(x, y, w, h) # 緑のグラデの三角形を描画
self.draw_line(x, y, w, h) # 線を描画
# テキストを描画
self.draw_info()
# バッファ切り替え (ダブルバッファ時)
# glutSwapBuffers()
# OpenGL描画実行 (シングルバッファ時?)
# glFlush()
# pygameダブルバッファ交換
pygame.display.flip()
def draw_text(self, x, y, st):
"""文字列をビットマップフォントで描画"""
glColor3f(1.0, 1.0, 1.0)
glRasterPos3f(x, y, -3.0)
for s in st:
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, ord(s))
def draw_info(self):
"""現在の状態をテキスト描画する"""
lyadd = -(self.view_hh / 12.0)
lx = -(self.view_wh * 0.95)
ly = self.view_hh + lyadd
strlist = []
strlist.append(self.cap)
strlist.append("P: " + ("Pers" if not self.flag2d else "Ortho"))
strlist.append("W: " + ("Wireframe" if self.wireframe else "Solid"))
strlist.append("L: Light " + ("On" if self.light_enable else "Off"))
strlist.append("T: " + (["GL_REPLACE",
"GL_MODULATE",
"GL_DECAL"][self.tex_mode]))
strlist.append("S: PointSprite " + ("On" if self.point_spr else "Off"))
strlist.append("F: " + ("Full" if self.fullscr else "Wdw"))
strlist.append("B: Pause")
strlist.append("ESC,Q : EXIT")
for s in strlist:
self.draw_text(lx, ly, s)
ly += lyadd
def draw_polygon_tex(self, x, y, z, tx, ty, vx, vy, texid):
"""テクスチャ付きポリゴンを描画"""
col = self.texcol
glFrontFace(GL_CCW) # 頂点反時計回りを表として扱う
# 頂点配列を作成
vertices = [-1.0, -1.0, 0.0, # 左下
1.0, -1.0, 0.0, # 右下
1.0, 1.0, -25.0, # 右上
- 1.0, 1.0, -25.0 # 左上
]
# テクスチャ座標配列を作成
texcoords = [0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
0.0, 0.0
]
# カラー配列を作成
colors = [col, col, 0.5, 1.0,
col, col, 0.5, 1.0,
col, col, 0.0, 1.0,
col, col, 0.0, 1.0
]
# 使うテクスチャを選択
glBindTexture(GL_TEXTURE_2D, self.tex[texid])
# テクスチャを透過にする
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glLoadIdentity()
glTranslatef(x, y, z) # 平行移動
glRotatef(self.angle / 2.0, 0.0, 0.0, 1.0) # 回転
glScale(vx, vy, 1.0) # 拡大縮小
# 頂点配列、テクスチャ座標配列、カラー配列有効化
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
# 頂点配列、テクスチャ座標配列、カラー配列を指定
glVertexPointer(3, GL_FLOAT, 0, vertices)
glTexCoordPointer(2, GL_FLOAT, 0, texcoords)
glColorPointer(4, GL_FLOAT, 0, colors)
glEnable(GL_TEXTURE_2D) # テクスチャを有効に
# ポリゴンとして描画
glDrawElements(GL_QUADS, 4, GL_UNSIGNED_BYTE, [0, 1, 2, 3])
# glDrawArrays(GL_POLYGON, 0, 4)
glDisable(GL_TEXTURE_2D) # テクスチャを無効に
# 頂点配列、テクスチャ座標配列、カラー配列無効化
glDisableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
glDisableClientState(GL_COLOR_ARRAY)
def draw_box(self, x, y, w, h):
"""赤いグラデの四角形を描く"""
glFrontFace(GL_CCW) # 頂点反時計回りを表とする
h /= 10.0
w = h
z = -40.0
glLoadIdentity()
glBegin(GL_QUADS) # 描画開始
glColor3f(0.5, 0.0, 0.0) # 色を指定
glVertex3f(x - w, y - h, z) # 左下
glColor3f(0.5, 0.0, 0.0)
glVertex3f(x + w, y - h, z) # 右下
glColor3f(1.0, 0.0, 0.0)
glVertex3f(x + w, y + h, z) # 右上
glColor3f(1.0, 0.0, 0.0)
glVertex3f(x - w, y + h, z) # 左上
glEnd() # 描画終了
def draw_tri(self, x, y, w, h):
"""緑のグラデの三角形を描く"""
glFrontFace(GL_CCW) # 頂点反時計回りを表とする
z = -50.0
glBegin(GL_TRIANGLES) # 三角形描画開始
glColor4f(0.0, 1.0, 0.0, 1.0) # 色を指定
glVertex3f(-w, -h, z) # 左下
glVertex3f(w, -h, z) # 右下
glColor4f(0.0, 0.2, 0.0, 0.2)
glVertex3f(x, y, z) # 上
glEnd()
def draw_line(self, x, y, w, h):
"""線を描く"""
z = -5.0
glColor3f(0.0, 1.0, 1.0) # 水色
glLineWidth(self.line_width) # 線のサイズ
glBegin(GL_LINES)
glVertex3f(-w, y, z) # 始点
glVertex3f(w, y, z) # 終点
glVertex3f(x, h, z) # 始点
glVertex3f(x, -h, z) # 終点
glEnd()
def draw_point(self, startang, r):
"""点を描く"""
glLoadIdentity()
z_d = 10
zadd = (float(self.mvfrm) / 5.0) % float(z_d)
# アルファブレンディングを有効化
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_BLEND)
if self.point_spr:
# ポイントスプライト有効時
glEnable(GL_POINT_SPRITE) # ポイントスプライトを有効化
glDisable(GL_POINT_SMOOTH) # 点のAAを無効化
glEnable(GL_TEXTURE_2D) # テクスチャを有効化
# テクスチャに色指定を反映させるよう指定
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
# 使うテクスチャを選択
glBindTexture(GL_TEXTURE_2D, self.tex[2])
glEnable(GL_ALPHA_TEST) # アルファテストを有効化
glPointSize(64.0) # 点のサイズを指定
# 距離に応じて点の大きさを変える
glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,
[0.0, 0.0, 0.02])
glBegin(GL_POINTS) # 点の描画開始を指定
lang = math.radians(startang)
langadd = math.radians(20)
for z in range(-40, -5, z_d):
# 奥行を変えて描画
zz = z + zadd
v = (30.0 + zz + 10.0) / 30.0
if v > 1.0:
v = 1.0
for i in range(0, 360, 20):
# 円を描くように描画
x = r * math.cos(lang)
y = r * math.sin(lang)
glColor3f(v, v, 0.5) # 色を指定
glVertex3f(x, y, zz) # 点座標を指定
lang += langadd
glEnd()
# 距離に応じて点のサイズを変えるソレに初期値を入れてリセット
glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, [1.0, 0.0, 0.0])
glDisable(GL_ALPHA_TEST) # アルファテストを無効化
glDisable(GL_POINT_SPRITE) # ポイントスプライトを無効化
self.set_tex_mode()
else:
# ポイントスプライト無効時
glDisable(GL_TEXTURE_2D) # テクスチャを無効化
glDisable(GL_POINT_SPRITE) # point_sprite を無効化
glEnable(GL_POINT_SMOOTH) # 点のAAを有効化
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST) # AAの品質を参考に
glPointSize(3.0) # 点のサイズ
# 距離に応じて点の大きさを変えない
glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, [1.0, 0.0, 0.0])
glBegin(GL_POINTS)
lang = math.radians(startang)
langadd = math.radians(10)
for z in range(-40, -5, z_d):
# 奥行を変えて描画
zz = z + zadd
v = (30.0 + zz + 10.0) / 30.0
if v > 1.0:
v = 1.0
for i in range(0, 360, 10):
# 円を描くように描画
x = r * math.cos(lang)
y = r * math.sin(lang)
glColor3f(v, v, 0.5) # 色を指定
glVertex3f(x, y, zz) # 点座標を指定
lang += langadd
glEnd()
glDisable(GL_TEXTURE_2D) # テクスチャを無効化
def set_material(self, kind):
"""マテリアルを設定"""
matdata = [
[mat_ambient, mat_diffuse, no_mat, no_shininess, no_mat],
[no_mat, mat_diffuse, mat_specular, low_shininess, no_mat],
[no_mat, mat_diffuse, mat_specular, high_shininess, no_mat],
[no_mat, mat_diffuse, no_mat, no_shininess, mat_emission]
]
dt = matdata[kind]
glMaterialfv(GL_FRONT, GL_AMBIENT, dt[0])
glMaterialfv(GL_FRONT, GL_DIFFUSE, dt[1])
glMaterialfv(GL_FRONT, GL_SPECULAR, dt[2])
glMaterialfv(GL_FRONT, GL_SHININESS, dt[3])
glMaterialfv(GL_FRONT, GL_EMISSION, dt[4])
def draw_teapot(self):
"""ティーポットを描く"""
glFrontFace(GL_CW) # teapotは頂点時計回りが表。他と逆なので注意。
glEnable(GL_DEPTH_TEST) # 隠面消去を有効化
glDisable(GL_CULL_FACE) # カリング無効化
# teapotだけはテクスチャを反映できるので、テクスチャを無効にしておく。
# cubeやsphere等はテクスチャを反映できない。
glDisable(GL_TEXTURE_2D)
self.set_material(1) # マテリアルの設定
# 平行移動、回転、拡大縮小は、
# 下に書いてある変換のほうから先に実行される
glLoadIdentity()
glTranslatef(-6.0, 0.0, -10.0) # 平行移動
glRotatef(self.xrot, 1.0, 0.0, 0.0) # x軸に沿って回転
glRotatef(self.yrot, 0.0, 1.0, 0.0) # y軸に沿って回転
glScale(1.0, 1.0, 1.0) # 拡大縮小
glColor3f(1.0, 0.0, 0.0) # 色を赤に(照明利用時は無視される)
if self.wireframe:
# ワイヤーフレームで描画
glLineWidth(self.line_width) # 線のサイズ
glutWireTeapot(2.0)
else:
# ソリッドで描画
glutSolidTeapot(2.0)
def draw_cube(self):
"""立方体を描画"""
glFrontFace(GL_CCW) # cubeは頂点反時計回りが表扱い
glEnable(GL_CULL_FACE) # カリング有効化
glCullFace(GL_BACK) # 裏面をカリングするように指定
self.set_material(0) # マテリアルの設定
glLoadIdentity()
glTranslatef(0.0, 0.0, -15.0)
glRotatef(self.angle, 0.0, 1.0, 1.0) # y軸、z軸に沿って回転
glScale(1.0, 1.0, self.scale / 2)
glColor3f(0.0, 1.0, 0.0) # 色を緑に
if self.wireframe:
glLineWidth(self.line_width)
glutWireCube(3.0)
else:
glutSolidCube(3.0)
def draw_ball(self):
"""球を描画"""
glFrontFace(GL_CCW) # 球は頂点反時計回りが表扱い
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
self.set_material(2) # マテリアルの設定
glLoadIdentity()
glTranslatef(6.0, 0.0, -20.0)
glRotatef(self.angle, 1.0, 0.0, 0.0) # x軸に沿って回転
glScale(1.0, self.scale, 1.0)
glColor3f(1.0, 0.0, 1.0) # 色を紫に
if self.wireframe:
glLineWidth(self.line_width)
glutWireSphere(1.0, 10, 10)
else:
glutSolidSphere(1.0, 10, 10)
def on_event(self, event):
"""イベント発生時に呼ばれる処理"""
if event.type in self._eventMap:
self._eventMap[event.type](event)
def onQuit(self, event):
"""メインループを終了させるよう設定"""
self._running = False
def onKeyDown(self, event):
"""キーが押された瞬間に呼ばれる処理"""
if event.key == pygame.K_ESCAPE or event.unicode == u'q':
# ESCキーかqキーが押されたので終了
pygame.event.post(pygame.event.Event(pygame.QUIT))
elif event.key == pygame.K_UP:
# 上キーが押された
self.xspeed -= 0.1
elif event.key == pygame.K_DOWN:
# 下キーが押された
self.xspeed += 0.1
elif event.key == pygame.K_LEFT:
# 左キーが押された
self.yspeed -= 0.1
elif event.key == pygame.K_RIGHT:
# 右キーが押された
self.yspeed += 0.1
elif event.key == pygame.K_l:
# 照明のon/off
self.light_enable = not self.light_enable
elif event.key == pygame.K_p:
# 平行投影/透視投影の切り替え
self.flag2d = not self.flag2d
elif event.key == pygame.K_w:
# ワイヤーフレーム/ソリッド描画の切り替え
self.wireframe = not self.wireframe
elif event.key == pygame.K_t:
# テクスチャモードの切り替え
self.tex_mode = (self.tex_mode + 1) % 3
md = [GL_REPLACE, GL_MODULATE, GL_DECAL]
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, md[self.tex_mode])
elif event.key == pygame.K_f:
# フルスクリーン/ウインドウの切り替え
self.fullscr = not self.fullscr
self.init_gl()
elif event.key == pygame.K_s:
# ポイントスプライトの切り替え
self.point_spr = not self.point_spr
elif event.key == pygame.K_b:
# ポーズ
self.pausefg = not self.pausefg
else:
print("KeyDown", event.unicode, event.key, event.mod)
def onKeyUp(self, event):
"""キーが離された瞬間に呼ばれる処理"""
# print("KeyUp", event.key, event.mod)
pass
def onMouseDown(self, event):
"""マウスボタンが押された瞬間に呼ばれる処理"""
lis = [
'unknown', # 0
'left', # 1
'middle', # 2
'right', # 3
'wheelup', # 4
'wheeldown' # 5
]
if event.button <= 5:
print('onMouseDown', lis[event.button], event.pos)
def onMouseUp(self, event):
"""マウスボタンが離された瞬間に呼ばれる処理"""
lis = [
'unknown', # 0
'left', # 1
'middle', # 2
'right', # 3
'wheelup', # 4
'wheeldown' # 5
]
if event.button <= 5:
print('onMouseUp ', lis[event.button], event.pos)
def onMouseMotion(self, event):
"""マウスカーソルが動いた時に呼ばれる処理"""
# print('onMouseMotion', event.pos, event.rel, event.buttons)
self.mx = event.pos[0]
self.my = event.pos[1]
def execute(self, w, h):
if not self.initialize(w, h):
return
timer = pygame.time.Clock()
# メインループ
while self._running:
timer.tick(60) # 60FPSを指定
for event in pygame.event.get():
self.on_event(event)
self.update()
self.draw()
self.frame += 1
self.cap = '%5.2f FPS' % (timer.get_fps())
# ウインドウタイトル文字列を指定
pygame.display.set_caption(self.cap)
pygame.quit()
if __name__ == "__main__" :
game = PyGame()
game.execute(800, 600)
@mieki256
Copy link
Author

Resource image. ( ./res/tex4.png )

tex4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment