Last active
April 10, 2024 01:31
-
-
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 で動作確認した。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Screenshots 1