X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=mesh_export.py;h=75db9d12dd1d1ab70faf9347c2b247f822155604;hb=982005bfbccb429767d0676bd840caf1118c9e21;hp=0e63d336aa2d1ad0a42bd409c94ca90718639359;hpb=79b9a1c86ecf81753934669d531679f29c6ab6e1;p=libs%2Fgl.git diff --git a/mesh_export.py b/mesh_export.py index 0e63d336..75db9d12 100644 --- a/mesh_export.py +++ b/mesh_export.py @@ -8,8 +8,149 @@ Group: 'Export' """ import sys +import math +import bpy import Blender +class Edge: + def __init__(self, me): + if me.__class__==Edge: + self._medge=me._medge + self.smooth=me.smooth + else: + self._medge=me + self.smooth=False + self.faces=[] + + def __getattr__(self, attr): + return getattr(self._medge, attr) + + def check_smooth(self, limit): + if len(self.faces)!=2: + return + + d=Blender.Mathutils.DotVecs(self.faces[0].no, self.faces[1].no) + if (d>limit and self.faces[0].smooth and self.faces[1].smooth) or d>0.999: + self.smooth=1 + + def other_face(self, f): + if f.index==self.faces[0].index: + if len(self.faces)>=2: + return self.faces[1] + else: + return None + else: + return self.faces[0] + + +class Vertex: + def __init__(self, mv): + if mv.__class__==Vertex: + self._mvert=mv._mvert + self.uv=mv.uv + else: + self._mvert=mv + self.uv=None + self.orig_index=self._mvert.index + + def __getattr__(self, attr): + return getattr(self._mvert, attr) + + +class Face: + def __init__(self, mf): + self._mface=mf + self.smooth_group=None + self.edges=[] + self.verts=[v for v in mf.verts] + self.flag=False + + def __getattr__(self, attr): + return getattr(self._mface, attr) + + def get_vertices_from(self, *vt): + indices=[u.index for u in vt] + flags=[(v.index in indices) for v in self.verts] + l=len(self.verts) + for i in range(l): + if flags[i] and not flags[(i+l-1)%l]: + return self.verts[i:]+self.verts[:i] + + +class SmoothGroup: + def __init__(self, index): + self.index=index + self.faces=[] + self.verts=[] + + def find_vertices(self): + vert_map={} + for f in self.faces: + for i in range(len(f.verts)): + v=f.verts[i] + if v.index not in vert_map: + vt=Vertex(v) + vt.index=len(self.verts) + self.verts.append(vt) + + vert_map[v.index]=vt + vt.no=Blender.Mathutils.Vector(f.no) + else: + vt=vert_map[v.index] + vt.no+=f.no + f.verts[i]=vt + + for v in self.verts: + v.no.normalize() + + def separate_uv(self): + copies={} + for f in self.faces: + for i in range(len(f.verts)): + v=f.verts[i] + if not v.uv: + v.uv=f.uv[i] + elif f.uv[i]!=v.uv: + if v.index not in copies: + copies[v.index]=[] + + vt=None + for w in copies[v.index]: + if w.uv==f.uv[i]: + vt=w + break + + if not vt: + vt=Vertex(v) + vt.index=len(self.verts) + vt.uv=f.uv[i] + self.verts.append(vt) + copies[v.index].append(vt) + + f.verts[i]=vt + + def create_edges(self): + edge_map={} + for f in self.faces: + vert_map=dict([(v.orig_index, v) for v in f.verts]) + for i in range(len(f.edges)): + v1=vert_map[f.edges[i].v1.index] + v2=vert_map[f.edges[i].v2.index] + key=tuple(sorted((v1.index, v2.index))) + + if key in edge_map: + e=edge_map[key] + else: + e=Edge(f.edges[i]) + edge_map[key]=e + e.v1=v1 + e.v2=v2 + e.key=key + + f.edges[i]=e + e.faces.append(f) + + class Exporter: def __init__(self, fn): self.filename=fn @@ -17,36 +158,197 @@ class Exporter: self.out_file=sys.stdout else: self.out_file=file(fn, "w") + self.use_strips=True + self.use_degen_tris=True + self.debug=False + + def find_smooth_group(self, face, sg): + face.smooth_group=sg + sg.faces.append(face) + queue=[face] + while queue: + cur=queue.pop(0) + for e in cur.edges: + if e.smooth: + other=e.other_face(cur) + if other and not other.smooth_group: + other.smooth_group=sg + sg.faces.append(other) + queue.append(other) + + def create_strip(self, face): + edge=None + for e in face.edges: + other=e.other_face(face) + if other and other.smooth_group.index==face.smooth_group.index and not other.flag: + edge=e + break + + if not edge: + return None + + if self.debug: + print "Starting strip from %s"%[v.index for v in face.verts] + + verts=face.get_vertices_from(edge.v1, edge.v2) + result=[verts[-2], verts[-1]] + + while 1: + verts=face.get_vertices_from(*result[-2:]) + k=len(result)%2 + if self.debug: + print " %d %s"%(len(result), [v.index for v in verts]) + + face.flag=True + if len(verts)==4 and not k: + result.append(verts[3]) + result.append(verts[2]) + if len(verts)==4 and k: + result.append(verts[3]) + + i1=result[-2].index + i2=result[-1].index + ekey=(min(i1, i2), max(i1, i2)) + for e in face.edges: + if e.key==ekey: + edge=e + break + + next=edge.other_face(face) + if not next or next.smooth_group.index!=face.smooth_group.index or next.flag: + break + face=next + + if self.debug: + print " %s"%[v.index for v in result] + + return result def export(self): - scene=Blender.Scene.GetCurrent() + scene=bpy.data.scenes.active - obj=scene.getActiveObject() + obj=scene.objects.active if obj.getType()!="Mesh": raise Exception, "Can only export Mesh data" mesh=obj.getData(mesh=True) - self.out_file.write("vertices NORMAL3,VERTEX3\n{\n") - for v in mesh.verts: - self.out_file.write("\tnormal3 %g %g %g;\n"%tuple(v.no)) - self.out_file.write("\tvertex3 %g %g %g;\n"%tuple(v.co)) - self.out_file.write("};\n") - self.out_file.write("batch TRIANGLES\n{\n") - for f in mesh.faces: - for i in range(2, len(f.verts)): - self.out_file.write("\tindices %u %u %u;\n"%(f.verts[0].index, f.verts[i-1].index, f.verts[i].index)) + faces=[Face(f) for f in mesh.faces] + + edges=dict([(e.key, Edge(e)) for e in mesh.edges]) + for f in faces: + for e in f.edge_keys: + edges[e].faces.append(f) + f.edges.append(edges[e]) + + smooth_limit=math.cos(mesh.degr*math.pi/180) + for e in edges.itervalues(): + e.check_smooth(smooth_limit) + + if self.debug: + print "%d faces, %d edges"%(len(faces), len(edges)) + + smooth_groups=[] + for f in faces: + if not f.smooth_group: + sg=SmoothGroup(len(smooth_groups)) + smooth_groups.append(sg) + self.find_smooth_group(f, sg) + + for sg in smooth_groups: + sg.find_vertices() + if mesh.faceUV: + sg.separate_uv() + sg.create_edges() + + verts=[] + for sg in smooth_groups: + for v in sg.verts: + v.index=len(verts) + verts.append(v) + + if self.debug: + print "%d smooth groups:"%(len(smooth_groups)) + for i in range(len(smooth_groups)): + sg=smooth_groups[i] + print " %d: %d faces, %d vertices"%(i, len(sg.faces), len(sg.verts)) + + strips=[] + if self.use_strips: + for sg in smooth_groups: + for f in sg.faces: + if not f.flag: + strip=self.create_strip(f) + if strip: + strips.append(strip) + + if self.use_degen_tris: + big_strip=[] + for s in strips: + if big_strip: + big_strip+=[big_strip[-1], s[0]] + big_strip+=s + + for f in faces: + if not f.flag: + if big_strip: + big_strip+=[big_strip[-1], f.verts[0]] + big_strip+=[f.verts[i] for i in (0, 1, -1)] + if len(f.verts)==4: + big_strip.append(f.verts[-2]) + f.flag=True + + strips=[big_strip] + + self.out_file.write("vertices NORMAL3") + if mesh.faceUV: + self.out_file.write("_TEXCOORD2") + self.out_file.write("_VERTEX3\n{\n") + norm=None + uv=None + for v in verts: + if v.no!=norm: + self.out_file.write("\tnormal3 %f %f %f;\n"%tuple(v.no)) + norm=v.no + if v.uv!=uv: + self.out_file.write("\ttexcoord2 %f %f;\n"%tuple(v.uv)) + uv=v.uv + self.out_file.write("\tvertex3 %f %f %f;\n"%tuple(v.co)) self.out_file.write("};\n") + for s in strips: + self.out_file.write("batch TRIANGLE_STRIP\n{\n\tindices") + n=0 + for v in s: + self.out_file.write(" %u"%v.index) + n+=1; + if n%32==0: + self.out_file.write(";\n\tindices") + self.out_file.write(";\n};\n") + + first=True + for f in faces: + if not f.flag: + if first: + self.out_file.write("batch TRIANGLES\n{\n") + first=False + for i in range(2, len(f.verts)): + self.out_file.write("\tindices %u %u %u;\n"%(f.verts[0].index, f.verts[i-1].index, f.verts[i].index)) + if not first: + self.out_file.write("};\n") + class FrontEnd: def run(self): #self.export(None) Blender.Window.FileSelector(self.export, "Export MSP GL mesh", Blender.sys.makename(ext='.mesh')) - + def export(self, fn): exp=Exporter(fn) + #exp.use_degen_tris=False + #exp.debug=True exp.export() + if __name__=="__main__": fe=FrontEnd() fe.run()