5 Name: 'MSP GL Mesh (.mesh)...'
15 def make_edge_key(i1, i2):
16 return (min(i1, i2), max(i1, i2))
20 def __init__(self, me):
21 if me.__class__==Edge:
29 def __getattr__(self, attr):
30 return getattr(self._medge, attr)
32 def __cmp__(self, other):
35 def check_smooth(self, limit):
36 if len(self.faces)!=2:
39 d=Blender.Mathutils.DotVecs(self.faces[0].no, self.faces[1].no)
40 if (d>limit and self.faces[0].smooth and self.faces[1].smooth) or d>0.999:
43 def other_face(self, f):
44 if f.index==self.faces[0].index:
45 if len(self.faces)>=2:
54 def __init__(self, mv):
55 if mv.__class__==Vertex:
61 self.orig_index=self._mvert.index
65 def __getattr__(self, attr):
66 return getattr(self._mvert, attr)
68 def __cmp__(self, other):
69 return cmp(self.index, other.index)
72 return "<Vert %d (%.4f, %.4f, %.4f) (%.4f, %.4f, %.4f)>"%(self.index, self.co[0], self.co[1], self.co[2], self.no[0], self.no[1], self.no[2])
78 def __init__(self, mf):
80 #self.smooth_group=None
82 self.verts=[v for v in mf.verts]
85 def __getattr__(self, attr):
86 return getattr(self._mface, attr)
88 def __cmp__(self, other):
89 return cmp(self.index, other.index)
92 return "<Face %d (%s)>"%(self.index, " ".join([str(v.index) for v in self.verts]))
96 def get_vertices_from(self, reverse, *vt):
100 indices=[u.index for u in vt]
101 flags=[(v.index in indices) for v in verts]
104 if flags[i] and not flags[(i+l-1)%l]:
105 return verts[i:]+verts[:i]
107 def get_edge(self, v1, v2):
108 key=make_edge_key(v1.index, v2.index)
115 def __init__(self, index):
120 def find_vertices(self):
123 for i in range(len(f.verts)):
125 if v.index not in vert_map:
127 vt.index=len(self.verts)
128 self.verts.append(vt)
131 vt.no=Blender.Mathutils.Vector(f.no)
140 def separate_uv(self):
143 for i in range(len(f.verts)):
148 if v.index not in copies:
152 for w in copies[v.index]:
159 vt.index=len(self.verts)
161 self.verts.append(vt)
162 copies[v.index].append(vt)
166 def create_edges(self):
169 vert_map=dict([(v.orig_index, v) for v in f.verts])
170 for i in range(len(f.edges)):
171 v1=vert_map[f.edges[i].v1.index]
172 v2=vert_map[f.edges[i].v2.index]
173 key=tuple(sorted((v1.index, v2.index)))
189 def __init__(self, m):
191 self.verts=[Vertex(v) for v in m.verts]
192 self.faces=[Face(f) for f in m.faces]
195 for i in range(len(f.verts)):
196 f.verts[i]=self.verts[f.verts[i].index]
197 f.verts[i].faces.append(f)
199 self.edges=dict([(e.key, Edge(e)) for e in m.edges])
201 for k in f.edge_keys:
203 e.faces.append(self.faces[f.index])
206 smooth_limit=math.cos(m.degr*math.pi/180)
207 for e in self.edges.itervalues():
208 e.v1=self.verts[e.v1.index]
209 e.v2=self.verts[e.v2.index]
210 e.check_smooth(smooth_limit)
212 def __getattr__(self, attr):
213 return getattr(self._mesh, attr)
215 def split_vertices(self, debug=False):
224 vg.append(self.find_group(v, f))
228 for i in range(len(self.verts)):
229 if len(groups[i])==1:
233 print "Vertex %s has %d groups"%(self.verts[i], len(groups[i]))
235 for g in groups[i][1:]:
236 v=Vertex(self.verts[i])
237 v.index=len(self.verts)
241 print " -> %d"%v.index
244 for j in range(len(f.edges)):
247 if e.v1!=self.verts[i] and e.v2!=self.verts[i]:
251 print " Splitting edge %s with faces %s"%(e.key, e.faces)
262 del self.edges[e.key]
264 if e.v1==self.verts[i]:
266 elif e.v2==self.verts[i]:
269 e.key=make_edge_key(e.v1.index, e.v2.index)
273 self.verts[i].faces.remove(f)
274 f.verts[f.verts.index(self.verts[i])]=v
277 def find_group(self, vert, face):
278 face_indices=[f.index for f in vert.faces]
285 other=e.other_face(f)
286 if not other or other.index not in face_indices:
296 def compute_normals(self):
299 print "WTF? Vertex %s without faces?"%v
300 v.no=Blender.Mathutils.Vector()
305 def create_strip(self, face, reverse, debug):
308 other=e.other_face(face)
309 if other and not other.flag:
317 print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], (edge.v1.index, edge.v2.index), reverse)
319 verts=face.get_vertices_from(reverse, edge.v1, edge.v2)
321 result=[verts[-1], verts[0]]
323 result=[verts[-2], verts[-1]]
326 verts=face.get_vertices_from(reverse, *result[-2:])
329 print " Adding %s"%face
332 if len(verts)==4 and not k:
333 result.append(verts[3])
334 result.append(verts[2])
335 if len(verts)==4 and k:
336 result.append(verts[3])
338 edge=face.get_edge(*result[-2:])
341 print " Next edge is %s"%(edge.key, )
343 next=edge.other_face(face)
344 if not next or next.flag:
349 print " %s"%[v.index for v in result]
355 def __init__(self, fn):
358 self.out_file=sys.stdout
360 self.out_file=file(fn, "w")
362 self.use_degen_tris=True
363 self.optimize_locality=True
365 self.strip_debug=False
366 self.smooth_debug=False
368 """def find_smooth_group(self, face, sg):
370 sg.faces.append(face)
376 other=e.other_face(cur)
377 if other and not other.smooth_group:
378 other.smooth_group=sg
379 sg.faces.append(other)
380 queue.append(other)"""
382 """def create_strip(self, face, reverse):
385 other=e.other_face(face)
386 if other and "other.smooth_group.index==face.smooth_group.index" and not other.flag:
394 print "Starting strip from %s, edge %s, reverse=%s"%([v.index for v in face.verts], edge.key, reverse)
396 verts=face.get_vertices_from(reverse, edge.v1, edge.v2)
398 result=[verts[-1], verts[0]]
400 result=[verts[-2], verts[-1]]
403 verts=face.get_vertices_from(reverse, *result[-2:])
406 print " Adding %s"%[v.index for v in verts]
409 if len(verts)==4 and not k:
410 result.append(verts[3])
411 result.append(verts[2])
412 if len(verts)==4 and k:
413 result.append(verts[3])
415 edge=face.get_edge(*result[-2:])
418 print " Next edge is %s"%((edge.v1.index, edge.v2.index), )
420 next=edge.other_face(face)
421 if not next or next.flag:
426 print " %s"%[v.index for v in result]
430 def get_locality(self, strip):
432 for i in range(1, len(strip)):
433 if strip[i].index!=strip[i-1].index:
434 total+=1.0/(abs(strip[i].index-strip[i-1].index))
435 return total/len(strip)
437 def get_followers(self, strip):
439 for i in range(len(strip)-1):
443 if v.index not in result:
445 if n.index not in result[v.index]:
446 result[v.index][n.index]=1
448 result[v.index][n.index]+=1
452 scene=bpy.data.scenes.active
454 obj=scene.objects.active
455 if obj.getType()!="Mesh":
456 raise Exception, "Can only export Mesh data"
458 mesh=Mesh(obj.getData(mesh=True))
461 ntris=sum([len(f.verts)-2 for f in mesh.faces])
462 print "Starting with %d vertices, %d faces (%d triangles) and %d edges"%(len(mesh.verts), len(mesh.faces), ntris, len(mesh.edges))
464 mesh.split_vertices(self.smooth_debug)
467 ntris=sum([len(f.verts)-2 for f in mesh.faces])
468 print "After splitting %d vertices, %d faces (%d triangles) and %d edges"%(len(mesh.verts), len(mesh.faces), ntris, len(mesh.edges))
470 mesh.compute_normals()
474 """faces=[Face(f) for f in mesh.faces]
476 edges=dict([(e.key, Edge(e)) for e in mesh.edges])
478 for e in f.edge_keys:
479 edges[e].faces.append(f)
480 f.edges.append(edges[e])
482 smooth_limit=math.cos(mesh.degr*math.pi/180)
483 for e in edges.itervalues():
484 e.check_smooth(smooth_limit)
487 ntris=sum([len(f.verts)-2 for f in faces])
488 print "%d faces (%d triangles), %d edges"%(len(faces), ntris, len(edges))
492 if not f.smooth_group:
493 sg=SmoothGroup(len(smooth_groups))
494 smooth_groups.append(sg)
495 self.find_smooth_group(f, sg)
497 for sg in smooth_groups:
504 for sg in smooth_groups:
510 print "%d smooth groups:"%len(smooth_groups)
511 for i in range(len(smooth_groups)):
513 print " %d: %d faces, %d vertices"%(i, len(sg.faces), len(sg.verts))
514 print "%d vertices total"%len(verts)"""
529 other=e.other_face(f)
530 if other and not other.flag:
532 if score>0 and score<best:
539 strip=mesh.create_strip(face, self.use_degen_tris and sum([len(s) for s in strips])%2, self.strip_debug)
544 print "%d strips:"%len(strips)
545 for i in range(len(strips)):
546 print " %d: %d indices"%(i, len(strips[i]))
547 print "%d loose faces"%len([f for f in mesh.faces if not f.flag])
548 nind=sum([len(s) for s in strips])+sum([len(f.verts) for f in mesh.faces if not f.flag])
549 print "%d indices total"%nind
551 if self.use_degen_tris:
555 big_strip+=[big_strip[-1], s[0]]
565 big_strip+=[big_strip[-1], f.verts[order[0]]]
566 big_strip+=[f.verts[i] for i in order[:len(f.verts)]]
573 print "Big strip has %d indices"%len(big_strip)
576 print "%.2f indices per triangle"%(float(nind)/ntris)
577 print "Locality before optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips])
579 if self.optimize_locality and self.use_strips:
582 followers.update(self.get_followers(s))
591 if vert.index in followers:
592 flw=followers[vert.index]
595 if flw[n]>best and not mesh.verts[n].flag:
597 best=flw[n]+0.9/abs(vert.index-n)
611 for i in range(len(mesh.verts)):
612 mesh.verts[i].index=i
615 print "Locality after optimization: "+" ".join(["%.3f"%self.get_locality(s) for s in strips])
617 self.out_file.write("vertices NORMAL3")
619 self.out_file.write("_TEXCOORD2")
620 self.out_file.write("_VERTEX3\n{\n")
625 self.out_file.write("\tnormal3 %f %f %f;\n"%tuple(v.no))
628 self.out_file.write("\ttexcoord2 %f %f;\n"%tuple(v.uv))
630 self.out_file.write("\tvertex3 %f %f %f;\n"%tuple(v.co))
631 self.out_file.write("};\n")
633 self.out_file.write("batch TRIANGLE_STRIP\n{\n\tindices")
636 self.out_file.write(" %u"%v.index)
639 self.out_file.write(";\n\tindices")
640 self.out_file.write(";\n};\n")
646 self.out_file.write("batch TRIANGLES\n{\n")
648 for i in range(2, len(f.verts)):
649 self.out_file.write("\tindices %u %u %u;\n"%(f.verts[0].index, f.verts[i-1].index, f.verts[i].index))
651 self.out_file.write("};\n")
656 self.use_strips=Blender.Draw.Create(True)
657 self.use_degen_tris=Blender.Draw.Create(True)
658 self.optimize_locality=Blender.Draw.Create(True)
659 self.debug=Blender.Draw.Create(False)
660 self.strip_debug=Blender.Draw.Create(False)
661 self.smooth_debug=Blender.Draw.Create(False)
662 ret=Blender.Draw.PupBlock("Export MSP GL mesh",
663 [("Use strips", self.use_strips, "Generage OpenGL triangle strips"),
664 ("Use degen tris", self.use_degen_tris, "Use degenerate triangles to combine triangle strips"),
665 ("Optimize locality", self.optimize_locality),
666 ("Debugging options"),
667 ("Debug", self.debug),
668 ("Debug strips", self.strip_debug),
669 ("Debug smoothing", self.smooth_debug)])
671 Blender.Window.FileSelector(self.export, "Export MSP GL mesh", Blender.sys.makename(ext='.mesh'))
676 def export(self, fn):
678 exp.use_strips=self.use_strips.val
679 exp.use_degen_tris=self.use_degen_tris.val
680 exp.optimize_locality=self.optimize_locality.val
681 exp.debug=self.debug.val
682 exp.strip_debug=self.strip_debug.val
683 exp.smooth_debug=self.smooth_debug.val
687 if __name__=="__main__":