+ return result
+
+
+class Exporter:
+ def __init__(self, fn):
+ self.filename = fn
+ if fn==None:
+ 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.export_lines = True
+ self.tbn_vecs = False
+ self.debug = False
+ self.strip_debug = False
+ self.split_debug = False
+
+ 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 = bpy.data.scenes.active
+
+ obj = scene.objects.active
+ if obj.getType()!="Mesh":
+ raise Exception, "Can only export Mesh data"
+
+ mesh = Blender.Mesh.New("export_tmp")
+ mesh.getFromObject(obj)
+ mesh = Mesh(mesh)
+
+ if self.debug:
+ ntris = sum([len(f.verts)-2 for f in mesh.faces])
+ print "Starting with %d vertices, %d faces (%d triangles) and %d edges"%(len(mesh.verts), len(mesh.faces), ntris, len(mesh.edges))
+
+ mesh.split_smooth(self.split_debug)
+
+ if self.debug:
+ print "After smooth splitting %d vertices and %d edges"%(len(mesh.verts), len(mesh.edges))
+
+ mesh.compute_normals()
+
+ if mesh.faceUV:
+ mesh.split_uv(self.split_debug)
+ if self.debug:
+ print "After UV splitting %d vertices and %d edges"%(len(mesh.verts), len(mesh.edges))
+
+ mesh.compute_uv()
+ if self.tbn_vecs:
+ mesh.compute_tbn()
+
+ strips = []
+ if self.use_strips:
+ for f in mesh.faces:
+ f.flag = False
+
+ while 1:
+ best = 5
+ face = None
+ for f in mesh.faces:
+ if f.flag:
+ continue
+ score = 0
+ for e in f.edges:
+ other = e.other_face(f)
+ if other and not other.flag:
+ score += 1
+ if score>0 and score<best:
+ face = f
+ best = score
+
+ if not face:
+ break
+
+ strip = mesh.create_strip(face, self.use_degen_tris and sum([len(s) for s in strips])%2, self.strip_debug)
+ if strip:
+ strips.append(strip)
+
+ if self.debug:
+ print "%d strips:"%len(strips)
+ for i in range(len(strips)):
+ print " %d: %d indices"%(i, len(strips[i]))
+ print "%d loose faces"%len([f for f in mesh.faces if not f.flag])
+ nind = sum([len(s) for s in strips])+sum([len(f.verts) for f in mesh.faces if not f.flag])
+ print "%d indices total"%nind
+
+ if self.use_degen_tris and strips:
+ big_strip = []
+ for s in strips:
+ if big_strip:
+ big_strip += [big_strip[-1], s[0]]
+ big_strip += s
+
+ for f in mesh.faces:
+ if not f.flag:
+ if len(big_strip)%2:
+ order = (-1, -2, 0, 1)
+ else:
+ order = (0, 1, -1, -2)
+ if big_strip:
+ big_strip += [big_strip[-1], f.verts[order[0]]]
+ big_strip += [f.verts[i] for i in order[:len(f.verts)]]
+ f.flag = True
+
+ strips = [big_strip]
+
+ if self.debug:
+ nind = len(big_strip)
+ print "Big strip has %d indices"%len(big_strip)
+
+ if self.debug:
+ print "%.2f indices per triangle"%(float(nind)/max(ntris, 1))
+ print "Locality before optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips])
+
+ if self.optimize_locality and self.use_strips and strips:
+ followers = {}
+ for s in strips:
+ followers.update(self.get_followers(s))
+
+ verts2 = []
+ vert = strips[0][0]
+ while 1:
+ vert.flag = True
+ verts2.append(vert)
+
+ next = None
+ if vert.index in followers:
+ flw = followers[vert.index]
+ best = 0
+ for n in flw:
+ if flw[n]>best and not mesh.verts[n].flag:
+ next = mesh.verts[n]
+ best = flw[n]+0.9/abs(vert.index-n)
+
+ if not next:
+ for v in mesh.verts:
+ if not v.flag:
+ next = v
+ break
+ if not next:
+ break
+
+ vert = next
+
+ mesh.verts = verts2
+
+ for i in range(len(mesh.verts)):
+ mesh.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")
+ if self.tbn_vecs:
+ self.out_file.write("_ATTRIB33_ATTRIB34")
+ self.out_file.write("_VERTEX3\n{\n")
+ norm = None
+ uv = None
+ tan = None
+ bino = None
+ for v in mesh.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
+ if v.tan!=tan:
+ self.out_file.write("\tattrib3 3 %f %f %f;\n"%tuple(v.tan))
+ tan = v.tan
+ if v.bino!=bino:
+ self.out_file.write("\tattrib3 4 %f %f %f;\n"%tuple(v.bino))
+ bino = v.bino
+ self.out_file.write("\tvertex3 %f %f %f;\n"%tuple(v.co))