X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=mesh_export.py;h=dd8e5414e95ab3dcb3531eb968aec7d96c5f215e;hb=5c59a04e253bf7868796fc0dc8e9768ad1988b33;hp=932433360f93649db45d61b6c63b290990a37f0b;hpb=b31a5873556fe046488587568fe35236227e3606;p=libs%2Fgl.git diff --git a/mesh_export.py b/mesh_export.py index 93243336..dd8e5414 100644 --- a/mesh_export.py +++ b/mesh_export.py @@ -9,13 +9,18 @@ Group: 'Export' import sys import math +import bpy import Blender class Edge: def __init__(self, me): - self._medge=me + if me.__class__==Edge: + self._medge=me._medge + self.smooth=me.smooth + else: + self._medge=me + self.smooth=False self.faces=[] - self.smooth=False def __getattr__(self, attr): return getattr(self._medge, attr) @@ -42,8 +47,12 @@ 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 + self.flag=False def __getattr__(self, attr): return getattr(self._mvert, attr) @@ -55,13 +64,33 @@ class Face: 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, reverse, *vt): + verts=self.verts[:] + if reverse: + verts.reverse() + indices=[u.index for u in vt] + flags=[(v.index in indices) for v in verts] + l=len(verts) + for i in range(l): + if flags[i] and not flags[(i+l-1)%l]: + return verts[i:]+verts[:i] + + def get_edge(self, v1, v2): + i1=v1.index + i2=v2.index + for e in self.edges: + if (e.v1.index==i1 or e.v1.index==i2) and (e.v2.index==i1 or e.v2.index==i2): + return e + class SmoothGroup: - def __init__(self): + def __init__(self, index): + self.index=index self.faces=[] self.verts=[] @@ -72,13 +101,65 @@ class SmoothGroup: v=f.verts[i] if v.index not in vert_map: vt=Vertex(v) - if not f.smooth: - vt.no=f.no + 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: - f.verts[i]=vert_map[v.index] + 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: @@ -88,25 +169,99 @@ class Exporter: self.out_file=sys.stdout else: self.out_file=file(fn, "w") + self.use_strips=True + self.use_degen_tris=True + self.optimize_locality=True + self.debug=False + self.strip_debug=False def find_smooth_group(self, face, sg): face.smooth_group=sg sg.faces.append(face) queue=[face] while queue: - f=queue.pop(0) - for e in f.edges: + cur=queue.pop(0) + for e in cur.edges: if e.smooth: - f2=e.other_face(f) - if f2 and not f2.smooth_group: - f2.smooth_group=sg - sg.faces.append(f2) - queue.append(f2) + 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, reverse): + 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.strip_debug: + print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], (edge.v1.index, edge.v2.index), reverse) + + verts=face.get_vertices_from(reverse, edge.v1, edge.v2) + if len(verts)==3: + result=[verts[-1], verts[0]] + else: + result=[verts[-2], verts[-1]] + + while 1: + verts=face.get_vertices_from(reverse, *result[-2:]) + k=len(result)%2 + if self.strip_debug: + print " Adding %s"%[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]) + + edge=face.get_edge(*result[-2:]) + + if self.strip_debug: + print " Next edge is %s"%((edge.v1.index, edge.v2.index), ) + + 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.strip_debug: + print " %s"%[v.index for v in result] + + return result + + def get_locality(self, strip): + total=0 + for i in range(1, len(strip)): + if strip[i].index!=strip[i-1].index: + total+=1.0/(abs(strip[i].index-strip[i-1].index)) + return total/len(strip) + + def get_followers(self, strip): + result={} + for i in range(len(strip)-1): + v=strip[i] + n=strip[i+1] + if v.index!=n.index: + if v.index not in result: + result[v.index]={} + if n.index not in result[v.index]: + result[v.index][n.index]=1 + else: + result[v.index][n.index]+=1 + 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" @@ -124,39 +279,196 @@ class Exporter: for e in edges.itervalues(): e.check_smooth(smooth_limit) + if self.debug: + ntris=sum([len(f.verts)-2 for f in faces]) + print "%d faces (%d triangles), %d edges"%(len(faces), ntris, len(edges)) + smooth_groups=[] for f in faces: if not f.smooth_group: - sg=SmoothGroup() + sg=SmoothGroup(len(smooth_groups)) smooth_groups.append(sg) self.find_smooth_group(f, sg) - verts=[] 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) - self.out_file.write("vertices NORMAL3_VERTEX3\n{\n") + 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)) + print "%d vertices total"%len(verts) + + strips=[] + if self.use_strips: + while 1: + best=5 + face=None + for f in faces: + if f.flag: + continue + score=0 + for e in f.edges: + other=e.other_face(f) + if other and other.smooth_group.index==f.smooth_group.index and not other.flag: + score+=1 + if score>0 and scorebest and not verts[n].flag: + next=verts[n] + best=flw[n]+0.9/abs(vert.index-n) + + if not next: + for v in verts: + if not v.flag: + next=v + break + if not next: + break + + vert=next + + verts=verts2 + + for i in range(len(verts)): + verts[i].index=i + + if self.debug: + print "Locality after optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips]) + + 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: - self.out_file.write("\tnormal3 %g %g %g;\n"%tuple(v.no)) - self.out_file.write("\tvertex3 %g %g %g;\n"%tuple(v.co)) + 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") - self.out_file.write("batch TRIANGLES\n{\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: - 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)) - self.out_file.write("};\n") + 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')) + self.use_strips=Blender.Draw.Create(True) + self.use_degen_tris=Blender.Draw.Create(True) + self.optimize_locality=Blender.Draw.Create(True) + self.debug=Blender.Draw.Create(False) + self.strip_debug=Blender.Draw.Create(False) + ret=Blender.Draw.PupBlock("Export MSP GL mesh", + [("Use strips", self.use_strips, "Generage OpenGL triangle strips"), + ("Use degen tris", self.use_degen_tris, "Use degenerate triangles to combine triangle strips"), + ("Optimize locality", self.optimize_locality), + ("Debugging options"), + ("Debug", self.debug), + ("Debug strips", self.strip_debug)]) + if ret: + Blender.Window.FileSelector(self.export, "Export MSP GL mesh", Blender.sys.makename(ext='.mesh')) + + def draw(self): + pass def export(self, fn): exp=Exporter(fn) + exp.use_strips=self.use_strips.val + exp.use_degen_tris=self.use_degen_tris.val + exp.optimize_locality=self.optimize_locality.val + exp.debug=self.debug.val + exp.strip_debug=self.strip_debug.val exp.export()