mqo読み込み機能を作ってみた
http://www.metaseq.net/metaseq/format.html
を見ながらmqoの読み込み機能を作った(頂点と面のみ)。
python自体に不慣れだったのでちょっと時間がかかったけど、
iteratorとlistの内包表現はおもしろいですな。
しかし、正規表現ではまった。
^hoge(\s+\w+)*
というようなパターンのカッコ内の繰り返しを取る方法がわからなかった。
groupsじゃ取れなさそうだが。
やむを得ず
\s+(?=\w+)
でsplitしてからごにょごにょすることにした。
いずれやり方がわかるじゃろぅ。
参考にしたサイト
rubyからの移行だとこの辺の情報がありがたい。pop(0)は知らないと無理
# -*- coding: utf-8 -*- # mqoファイルの読み込み import re class Object: def __init__(self): self.objects=[] pass def Load(self, io): print "mqo.load" self.io=io # ヘッダ if not io.next().startswith("Metasequoia Document"): return False m=re.match('^Format (\w+) Ver (\d+)\.(\d+)', io.next()) if m.group(1)!="Text": return False if m.group(2)!="1": return False print "Format: %s, Version %s.%s" % (m.group(1), m.group(2), m.group(3)) try: while True: chunk=self.Chunk()[0].lower() print "#%s" % (chunk) if chunk=="scene": # 1回 self.scene=self.ChunkScene() elif chunk=="material": # 1回 self.material=self.ChunkMaterial() elif chunk=="object": # 複数あり self.objects.append(self.ChunkObject()) except StopIteration: # end return def Chunk(self): while True: line=self.io.next().strip() m=re.match('^(\w+)\s*(\d+)?\s*{', line) if m: return (m.group(1), m.group(2)) m=re.match('^Object\s*"([^"]+)"\s+{', line) if m: return ('object', m.group(1)) def ChunkScene(self): scene={} while True: line=self.io.next().strip() if line=='}': break # fields=line.split() scene[fields.pop(0)]=fields return scene def ChunkMaterial(self): materials=[] # match()で取れない? # recomp=re.compile(r""" #"([^)]*)" #1 材質名 #(?:\s+ # (\w+) # パラメータ # \( # ([^)]*) # 値 # \) #)* # """, re.VERBOSE) recomp=re.compile(r""" \s+ (?= \w+ # パラメータ \( [^)]* # 値 \) ) """, re.VERBOSE) while True: material={} line=self.io.next().strip() if line=='}': break # fields=recomp.split(line) material['name']=fields.pop(0)[1:-1] for field in fields: m=re.match('^(\w+)\(([^)]*)\)', field) if m: values=m.group(2).split() if len(values)>1: material[m.group(1)]=values else: material[m.group(1)]=m.group(2) materials.append(material) return materials def ChunkObject(self): object={} while True: line=self.io.next().strip() if line=='}': break # m=re.match('^(\w+)\s*(\d+)?\s*{', line) if m: chunk=m.group(1).lower() if m.group(1)=="vertex": object["vertex"]=self.ChunkVertex() elif chunk=="bvertex": object["bvertex"]="not implemented" elif m.group(1)=="face": object["face"]=self.ChunkFace() else: fields=line.split() object[fields.pop(0)]=fields return object def ChunkVertex(self): vertex=[] while True: line=self.io.next().strip() if line=='}': break # vertex.append([float(i) for i in line.split()]) return vertex def ChunkFace(self): face=[] recomp=re.compile(r""" ^(\w+)\s* #1 頂点数 V\(([^)]*)\)\s* #2 頂点インデックス M\(([^)]*)\)\s* #3 材質インデックス UV\(([^)]*)\)\s* #4 UV値 (?:COL\(([^)]*)\))? #5 頂点カラー """, re.VERBOSE) while True: line=self.io.next().strip() if line=='}': break # m=recomp.match(line) if m: face.append({ "index": [int(i) for i in m.group(2).split()], "material": int(m.group(3)), "uv": [float(i) for i in m.group(4).split()] }) if m.group(5): face["color"]=m.group(5) return face ################################################################################ # test ################################################################################ if __name__=='__main__': def test(): o=Object() #o.Load(open("cube.mqo")) o.Load(open("miry01.mqo")) import timeit t = timeit.Timer('test()', 'from __main__ import test') print "%.6f sec" % (t.timeit(1))
それで、さっそくネットからフリーの形状データを落として試してみたのだが、
表示が有り得ない遅さになってしまっていた。
OpenGLの方の最適化が必要の様子。