5 Name: 'MSP GL Mesh (.mesh)...'
16 def __init__(self, me):
17 if me.__class__==Edge:
25 def __getattr__(self, attr):
26 return getattr(self._medge, attr)
28 def check_smooth(self, limit):
29 if len(self.faces)!=2:
32 d=Blender.Mathutils.DotVecs(self.faces[0].no, self.faces[1].no)
33 if (d>limit and self.faces[0].smooth and self.faces[1].smooth) or d>0.999:
36 def other_face(self, f):
37 if f.index==self.faces[0].index:
38 if len(self.faces)>=2:
47 def __init__(self, mv):
48 if mv.__class__==Vertex:
54 self.orig_index=self._mvert.index
57 def __getattr__(self, attr):
58 return getattr(self._mvert, attr)
62 def __init__(self, mf):
64 self.smooth_group=None
66 self.verts=[v for v in mf.verts]
69 def __getattr__(self, attr):
70 return getattr(self._mface, attr)
72 def get_vertices_from(self, reverse, *vt):
76 indices=[u.index for u in vt]
77 flags=[(v.index in indices) for v in verts]
80 if flags[i] and not flags[(i+l-1)%l]:
81 return verts[i:]+verts[:i]
83 def get_edge(self, v1, v2):
87 if (e.v1.index==i1 or e.v1.index==i2) and (e.v2.index==i1 or e.v2.index==i2):
92 def __init__(self, index):
97 def find_vertices(self):
100 for i in range(len(f.verts)):
102 if v.index not in vert_map:
104 vt.index=len(self.verts)
105 self.verts.append(vt)
108 vt.no=Blender.Mathutils.Vector(f.no)
117 def separate_uv(self):
120 for i in range(len(f.verts)):
125 if v.index not in copies:
129 for w in copies[v.index]:
136 vt.index=len(self.verts)
138 self.verts.append(vt)
139 copies[v.index].append(vt)
143 def create_edges(self):
146 vert_map=dict([(v.orig_index, v) for v in f.verts])
147 for i in range(len(f.edges)):
148 v1=vert_map[f.edges[i].v1.index]
149 v2=vert_map[f.edges[i].v2.index]
150 key=tuple(sorted((v1.index, v2.index)))
166 def __init__(self, fn):
169 self.out_file=sys.stdout
171 self.out_file=file(fn, "w")
173 self.use_degen_tris=True
174 self.optimize_locality=True
176 self.strip_debug=False
178 def find_smooth_group(self, face, sg):
180 sg.faces.append(face)
186 other=e.other_face(cur)
187 if other and not other.smooth_group:
188 other.smooth_group=sg
189 sg.faces.append(other)
192 def create_strip(self, face, reverse):
195 other=e.other_face(face)
196 if other and other.smooth_group.index==face.smooth_group.index and not other.flag:
204 print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], (edge.v1.index, edge.v2.index), reverse)
206 verts=face.get_vertices_from(reverse, edge.v1, edge.v2)
208 result=[verts[-1], verts[0]]
210 result=[verts[-2], verts[-1]]
213 verts=face.get_vertices_from(reverse, *result[-2:])
216 print " Adding %s"%[v.index for v in verts]
219 if len(verts)==4 and not k:
220 result.append(verts[3])
221 result.append(verts[2])
222 if len(verts)==4 and k:
223 result.append(verts[3])
225 edge=face.get_edge(*result[-2:])
228 print " Next edge is %s"%((edge.v1.index, edge.v2.index), )
230 next=edge.other_face(face)
231 if not next or next.smooth_group.index!=face.smooth_group.index or next.flag:
236 print " %s"%[v.index for v in result]
240 def get_locality(self, strip):
242 for i in range(1, len(strip)):
243 if strip[i].index!=strip[i-1].index:
244 total+=1.0/(abs(strip[i].index-strip[i-1].index))
245 return total/len(strip)
247 def get_followers(self, strip):
249 for i in range(len(strip)-1):
253 if v.index not in result:
255 if n.index not in result[v.index]:
256 result[v.index][n.index]=1
258 result[v.index][n.index]+=1
262 scene=bpy.data.scenes.active
264 obj=scene.objects.active
265 if obj.getType()!="Mesh":
266 raise Exception, "Can only export Mesh data"
268 mesh=obj.getData(mesh=True)
270 faces=[Face(f) for f in mesh.faces]
272 edges=dict([(e.key, Edge(e)) for e in mesh.edges])
274 for e in f.edge_keys:
275 edges[e].faces.append(f)
276 f.edges.append(edges[e])
278 smooth_limit=math.cos(mesh.degr*math.pi/180)
279 for e in edges.itervalues():
280 e.check_smooth(smooth_limit)
283 ntris=sum([len(f.verts)-2 for f in faces])
284 print "%d faces (%d triangles), %d edges"%(len(faces), ntris, len(edges))
288 if not f.smooth_group:
289 sg=SmoothGroup(len(smooth_groups))
290 smooth_groups.append(sg)
291 self.find_smooth_group(f, sg)
293 for sg in smooth_groups:
300 for sg in smooth_groups:
306 print "%d smooth groups:"%len(smooth_groups)
307 for i in range(len(smooth_groups)):
309 print " %d: %d faces, %d vertices"%(i, len(sg.faces), len(sg.verts))
310 print "%d vertices total"%len(verts)
322 other=e.other_face(f)
323 if other and other.smooth_group.index==f.smooth_group.index and not other.flag:
325 if score>0 and score<best:
330 strip=self.create_strip(face, self.use_degen_tris and sum([len(s) for s in strips])%2)
335 print "%d strips:"%len(strips)
336 for i in range(len(strips)):
337 print " %d: %d indices"%(i, len(strips[i]))
338 print "%d loose faces"%len([f for f in faces if not f.flag])
339 nind=sum([len(s) for s in strips])+sum([len(f.verts) for f in faces if not f.flag])
340 print "%d indices total"%nind
342 if self.use_degen_tris:
346 big_strip+=[big_strip[-1], s[0]]
356 big_strip+=[big_strip[-1], f.verts[order[0]]]
357 big_strip+=[f.verts[i] for i in order[:len(f.verts)]]
364 print "Big strip has %d indices"%len(big_strip)
367 print "%.2f indices per triangle"%(float(nind)/ntris)
368 print "Locality before optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips])
370 if self.optimize_locality and self.use_strips:
373 followers.update(self.get_followers(s))
382 if vert.index in followers:
383 flw=followers[vert.index]
386 if flw[n]>best and not verts[n].flag:
388 best=flw[n]+0.9/abs(vert.index-n)
402 for i in range(len(verts)):
406 print "Locality after optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips])
408 self.out_file.write("vertices NORMAL3")
410 self.out_file.write("_TEXCOORD2")
411 self.out_file.write("_VERTEX3\n{\n")
416 self.out_file.write("\tnormal3 %f %f %f;\n"%tuple(v.no))
419 self.out_file.write("\ttexcoord2 %f %f;\n"%tuple(v.uv))
421 self.out_file.write("\tvertex3 %f %f %f;\n"%tuple(v.co))
422 self.out_file.write("};\n")
424 self.out_file.write("batch TRIANGLE_STRIP\n{\n\tindices")
427 self.out_file.write(" %u"%v.index)
430 self.out_file.write(";\n\tindices")
431 self.out_file.write(";\n};\n")
437 self.out_file.write("batch TRIANGLES\n{\n")
439 for i in range(2, len(f.verts)):
440 self.out_file.write("\tindices %u %u %u;\n"%(f.verts[0].index, f.verts[i-1].index, f.verts[i].index))
442 self.out_file.write("};\n")
447 self.use_strips=Blender.Draw.Create(True)
448 self.use_degen_tris=Blender.Draw.Create(True)
449 self.optimize_locality=Blender.Draw.Create(True)
450 self.debug=Blender.Draw.Create(False)
451 self.strip_debug=Blender.Draw.Create(False)
452 ret=Blender.Draw.PupBlock("Export MSP GL mesh",
453 [("Use strips", self.use_strips, "Generage OpenGL triangle strips"),
454 ("Use degen tris", self.use_degen_tris, "Use degenerate triangles to combine triangle strips"),
455 ("Optimize locality", self.optimize_locality),
456 ("Debugging options"),
457 ("Debug", self.debug),
458 ("Debug strips", self.strip_debug)])
460 Blender.Window.FileSelector(self.export, "Export MSP GL mesh", Blender.sys.makename(ext='.mesh'))
465 def export(self, fn):
467 exp.use_strips=self.use_strips.val
468 exp.use_degen_tris=self.use_degen_tris.val
469 exp.optimize_locality=self.optimize_locality.val
470 exp.debug=self.debug.val
471 exp.strip_debug=self.strip_debug.val
475 if __name__=="__main__":