]> git.tdb.fi Git - libs/gl.git/blobdiff - mesh_export.py
Allow generic vertex attribute 0, since OpenGL 3.0 does not support any fixed-functio...
[libs/gl.git] / mesh_export.py
index fbb282281e3dce09e3ef3af62d14ec264a69f65b..41ceb90a7baed794eaf7fa1cf6cc6d0276efb5e2 100644 (file)
@@ -20,6 +20,8 @@ class Edge:
        def __init__(self, me):
                if me.__class__==Edge:
                        self._medge=me._medge
+                       self.v1=me.v1
+                       self.v2=me.v2
                        self.smooth=me.smooth
                else:
                        self._medge=me
@@ -54,6 +56,7 @@ class Vertex:
        def __init__(self, mv):
                if mv.__class__==Vertex:
                        self._mvert=mv._mvert
+                       self.no=mv.no
                        self.uv=mv.uv
                else:
                        self._mvert=mv
@@ -61,11 +64,15 @@ class Vertex:
                self.orig_index=self._mvert.index
                self.flag=False
                self.faces=[]
+               self.tan=None
+               self.bino=None
 
        def __getattr__(self, attr):
                return getattr(self._mvert, attr)
 
        def __cmp__(self, other):
+               if other is None:
+                       return 1
                return cmp(self.index, other.index)
 
        def __str__(self):
@@ -85,6 +92,8 @@ class Face:
                return getattr(self._mface, attr)
 
        def __cmp__(self, other):
+               if other is None:
+                       return 1
                return cmp(self.index, other.index)
 
        def __str__(self):
@@ -92,12 +101,11 @@ class Face:
        
        __repr__=__str__
 
-       def get_vertices_from(self, reverse, *vt):
+       def pivot_vertices(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]
+               flags=[(v in vt) for v in verts]
                l=len(verts)
                for i in range(l):
                        if flags[i] and not flags[(i+l-1)%l]:
@@ -108,6 +116,7 @@ class Face:
                for e in self.edges:
                        if e.key==key:
                                return e
+               raise KeyError, "No edge %s"%(key,)
 
 
 class Line:
@@ -151,7 +160,7 @@ class Mesh:
        def __getattr__(self, attr):
                return getattr(self._mesh, attr)
 
-       def split_vertices(self, debug=False):
+       def split_vertices(self, find_group_func, debug):
                groups=[]
                for v in self.verts:
                        for f in v.faces:
@@ -160,7 +169,7 @@ class Mesh:
                        vg=[]
                        for f in v.faces:
                                if not f.flag:
-                                       vg.append(self.find_group(v, f))
+                                       vg.append(find_group_func(v, f))
 
                        groups.append(vg)
 
@@ -177,7 +186,7 @@ class Mesh:
                                self.verts.append(v)
 
                                if debug:
-                                       print "  -> %d"%v.index
+                                       print "  -> %d %s"%(v.index, [f.index for f in g])
 
                                for f in g:
                                        for j in range(len(f.edges)):
@@ -189,15 +198,14 @@ class Mesh:
                                                if debug:
                                                        print "  Splitting edge %s with faces %s"%(e.key, e.faces)
 
-                                               if not e.smooth:
-                                                       if len(e.faces)>=2:
-                                                               k=e.faces.index(f)
-                                                               e.faces.remove(f)
-                                                               e=Edge(e)
-                                                               f.edges[j]=e
-                                                               e.faces.append(f)
-                                                       else:
-                                                               del self.edges[e.key]
+                                               if e.other_face(f) not in g and len(e.faces)>=2:
+                                                       k=e.faces.index(f)
+                                                       e.faces.remove(f)
+                                                       e=Edge(e)
+                                                       f.edges[j]=e
+                                                       e.faces.append(f)
+                                               else:
+                                                       del self.edges[e.key]
 
                                                if e.v1==self.verts[i]:
                                                        e.v1=v
@@ -205,23 +213,27 @@ class Mesh:
                                                        e.v2=v
 
                                                e.key=make_edge_key(e.v1.index, e.v2.index)
-                                               if not e.smooth:
-                                                       self.edges[e.key]=e
+                                               self.edges[e.key]=e
 
                                        self.verts[i].faces.remove(f)
                                        f.verts[f.verts.index(self.verts[i])]=v
                                        v.faces.append(f)
 
-       def find_group(self, vert, face):
-               face_indices=[f.index for f in vert.faces]
+       def split_smooth(self, debug=False):
+               self.split_vertices(self.find_smooth_group, debug)
+
+       def split_uv(self, debug=False):
+               self.split_vertices(self.find_uv_group, debug)
 
+       def find_smooth_group(self, vert, face):
                face.flag=True
                queue=[face]
 
                for f in queue:
                        for e in f.edges:
                                other=e.other_face(f)
-                               if not other or other.index not in face_indices:
+                               #if not other or other.index not in face_indices:
+                               if other not in vert.faces:
                                        continue
 
                                if e.smooth:
@@ -231,6 +243,16 @@ class Mesh:
 
                return queue
 
+       def find_uv_group(self, vert, face):
+               uv=face.uv[face.verts.index(vert)]
+               face.flag=True
+               group=[face]
+               for f in vert.faces:
+                       if not f.flag and f.uv[f.verts.index(vert)]==uv:
+                               f.flag=True
+                               group.append(f)
+               return group
+
        def compute_normals(self):
                for v in self.verts:
                        if v.faces:
@@ -242,6 +264,31 @@ class Mesh:
                                # XXX Should use edges to compute normal
                                v.no=Blender.Mathutils.Vector(0, 0, 1)
 
+       def compute_uv(self):
+               for v in self.verts:
+                       if v.faces:
+                               v.uv=v.faces[0].uv[v.faces[0].verts.index(v)]
+
+       def compute_tbn(self):
+               for v in self.verts:
+                       v.tan=Blender.Mathutils.Vector()
+                       v.bino=Blender.Mathutils.Vector()
+                       for f in v.faces:
+                               fverts=f.pivot_vertices(False, v)
+                               v1=fverts[1]
+                               v2=fverts[-1]
+                               du1=v1.uv[0]-v.uv[0]
+                               du2=v2.uv[0]-v.uv[0]
+                               dv1=v1.uv[1]-v.uv[1]
+                               dv2=v2.uv[1]-v.uv[1]
+                               div=du1*dv2-du2*dv1
+                               edge1=fverts[1].co-fverts[0].co
+                               edge2=fverts[-1].co-fverts[0].co
+                               v.tan+=(edge1*dv2-edge2*dv1)/div
+                               v.bino+=(edge2*du1-edge1*du2)/div
+                       v.tan.normalize()
+                       v.bino.normalize()
+
        def create_strip(self, face, reverse, debug):
                edge=None
                for e in face.edges:
@@ -256,14 +303,14 @@ class Mesh:
                if 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)
+               verts=face.pivot_vertices(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:])
+                       verts=face.pivot_vertices(reverse, *result[-2:])
                        k=len(result)%2
                        if debug:
                                print "  Adding %s"%face
@@ -302,9 +349,10 @@ class Exporter:
                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.smooth_debug=False
+               self.split_debug=False
 
        def get_locality(self, strip):
                total=0
@@ -340,14 +388,22 @@ class Exporter:
                        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_vertices(self.smooth_debug)
+               mesh.split_smooth(self.split_debug)
 
                if self.debug:
-                       ntris=sum([len(f.verts)-2 for f in mesh.faces])
-                       print "After splitting %d vertices, %d faces (%d triangles) and %d edges"%(len(mesh.verts), len(mesh.faces), ntris, len(mesh.edges))
+                       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:
@@ -452,9 +508,13 @@ class Exporter:
                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))
@@ -462,6 +522,12 @@ class Exporter:
                        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))
                self.out_file.write("};\n")
                for s in strips:
@@ -502,18 +568,20 @@ class FrontEnd:
                self.use_degen_tris=Blender.Draw.Create(self.config.get('use_degen_tris', True))
                self.optimize_locality=Blender.Draw.Create(self.config.get('optimize_locality', True))
                self.export_lines=Blender.Draw.Create(self.config.get('export_lines', False))
+               self.tbn_vecs=Blender.Draw.Create(self.config.get('tbn_vecs', False))
                self.debug=Blender.Draw.Create(self.config.get('debug', False))
                self.strip_debug=Blender.Draw.Create(self.config.get('strip_debug', False))
-               self.smooth_debug=Blender.Draw.Create(self.config.get('smooth_debug', False))
+               self.split_debug=Blender.Draw.Create(self.config.get('split_debug', 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),
-                               ("Export lines", self.export_lines),
+                               ("Export lines", self.export_lines, "Export lone edges as lines"),
+                               ("Compute T/B vecs", self.tbn_vecs, "Compute tangent/binormal vectors for bumpmapping"),
                                ("Debugging options"),
                                ("Debug", self.debug),
                                ("Debug strips", self.strip_debug),
-                               ("Debug smoothing", self.smooth_debug)])
+                               ("Debug splitting", self.split_debug)])
                if ret:
                        dirname=self.temp_config.get("dirname", Blender.sys.dirname(Blender.Get("filename")))
                        obj=bpy.data.scenes.active.objects.active
@@ -527,9 +595,10 @@ class FrontEnd:
                self.config['use_degen_tris']=self.use_degen_tris.val
                self.config['optimize_locality']=self.optimize_locality.val
                self.config['export_lines']=self.export_lines.val
+               self.config['tbn_vecs']=self.tbn_vecs.val
                self.config['debug']=self.debug.val
                self.config['strip_debug']=self.strip_debug.val
-               self.config['smooth_debug']=self.smooth_debug.val
+               self.config['split_debug']=self.split_debug.val
                Blender.Registry.SetKey('mspgl_export', self.config, True)
 
                import os
@@ -541,9 +610,10 @@ class FrontEnd:
                exp.use_degen_tris=self.use_degen_tris.val
                exp.optimize_locality=self.optimize_locality.val
                exp.export_lines=self.export_lines.val
+               exp.tbn_vecs=self.tbn_vecs.val
                exp.debug=self.debug.val
                exp.strip_debug=self.strip_debug.val
-               exp.smooth_debug=self.smooth_debug.val
+               exp.split_debug=self.split_debug.val
                exp.export()