--- /dev/null
+import math
+import mathutils
+
+def make_edge_key(i1, i2):
+ return (min(i1, i2), max(i1, i2))
+
+class Edge:
+ def __init__(self, me):
+ if me.__class__==Edge:
+ self._medge = me._medge
+ self.vertices = me.vertices[:]
+ self.smooth = me.smooth
+ else:
+ self._medge = me
+ self.smooth = False
+ self.faces = []
+
+ def __getattr__(self, attr):
+ return getattr(self._medge, attr)
+
+ def check_smooth(self, limit):
+ if len(self.faces)!=2:
+ return
+
+ d = self.faces[0].normal.dot(self.faces[1].normal)
+ if (d>limit and self.faces[0].use_smooth and self.faces[1].use_smooth) or d>0.999:
+ self.smooth = True
+
+ def other_face(self, f):
+ if f.index==self.faces[0].index:
+ if len(self.faces)>=2:
+ return self.faces[1]
+ else:
+ return None
+ else:
+ return self.faces[0]
+
+
+class Vertex:
+ def __init__(self, mv):
+ if mv.__class__==Vertex:
+ self._mvert = mv._mvert
+ self.normal = mv.normal
+ self.uv = mv.uv
+ else:
+ self._mvert = mv
+ self.uv = None
+ 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)
+
+
+class Face:
+ def __init__(self, mf):
+ self._mface = mf
+ self.edges = []
+ self.vertices = mf.vertices[:]
+ self.uv = None
+ self.flag = False
+ self.material = None
+
+ def __getattr__(self, attr):
+ return getattr(self._mface, attr)
+
+ def __cmp__(self, other):
+ if other is None:
+ return 1
+ return cmp(self.index, other.index)
+
+ def pivot_vertices(self, *vt):
+ flags = [(v in vt) for v in self.vertices]
+ l = len(self.vertices)
+ for i in range(l):
+ if flags[i] and not flags[(i+l-1)%l]:
+ return self.vertices[i:]+self.vertices[:i]
+
+ def get_edge(self, v1, v2):
+ key = make_edge_key(v1.index, v2.index)
+ for e in self.edges:
+ if e.key==key:
+ return e
+ raise KeyError("No edge %s"%(key,))
+
+
+class Line:
+ def __init__(self, e):
+ self.edge = e
+ self.vertices = e.vertices[:]
+ self.flag = False
+
+
+class Mesh:
+ def __init__(self, m):
+ self._mesh = m
+ self.vertices = [Vertex(v) for v in m.vertices]
+ self.faces = [Face(f) for f in m.faces]
+ self.materials = m.materials[:]
+ self.has_uv = False
+
+ uvtex = None
+ if m.uv_textures:
+ uvtex = self.uv_textures[0]
+ self.has_uv = True
+
+ for f in self.faces:
+ f.vertices = [self.vertices[i] for i in f.vertices]
+ if uvtex:
+ f.uv = uvtex.data[f.index].uv
+ for v in f.vertices:
+ v.faces.append(f)
+
+ self.edges = dict([(e.key, Edge(e)) for e in m.edges])
+ for f in self.faces:
+ for k in f.edge_keys:
+ e = self.edges[k]
+ e.faces.append(self.faces[f.index])
+ f.edges.append(e)
+
+ self.lines = [Line(e) for e in self.edges.values() if not e.faces]
+
+ if m.use_auto_smooth:
+ smooth_limit = math.cos(m.auto_smooth_angle*math.pi/180)
+ else:
+ smooth_limit = -1
+
+ for e in self.edges.values():
+ e.vertices = [self.vertices[i] for i in e.vertices]
+ e.check_smooth(smooth_limit)
+
+ def __getattr__(self, attr):
+ return getattr(self._mesh, attr)
+
+ def splice(self, other):
+ material_map = []
+ for m in other.materials:
+ if m in self.materials:
+ material_map.append(self.materials.index(m))
+ else:
+ material_map.append(len(self.materials))
+ self.materials.append(m)
+
+ offset = len(self.vertices)
+ for v in other.vertices:
+ v.index += offset
+ self.vertices.append(v)
+
+ offset = len(self.faces)
+ for f in other.faces:
+ f.index += offset
+ f.material = material_map[f.material_index]
+ self.faces.append(f)
+
+ for e in other.edges.values():
+ e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index)
+ self.edges[e.key] = e
+
+ self.lines += other.lines
+
+ def generate_material_uv(self):
+ for f in self.faces:
+ f.uv = ([(f.material_index+0.5)/len(self.materials), 0.5],)*len(f.vertices)
+ self.has_uv = True
+
+ def split_vertices(self, find_group_func, progress = None):
+ groups = []
+ for i in range(len(self.vertices)):
+ v = self.vertices[i]
+ for f in v.faces:
+ f.flag = False
+
+ vg = []
+ for f in v.faces:
+ if not f.flag:
+ vg.append(find_group_func(v, f))
+
+ groups.append(vg)
+
+ if progress:
+ progress.set_progress(i*0.5/len(self.vertices))
+
+ for i in range(len(self.vertices)):
+ if len(groups[i])==1:
+ continue
+
+ for g in groups[i][1:]:
+ v = Vertex(self.vertices[i])
+ v.index = len(self.vertices)
+ self.vertices.append(v)
+
+ for f in g:
+ for j in range(len(f.edges)):
+ e = f.edges[j]
+
+ if self.vertices[i] not in e.vertices:
+ continue
+
+ 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]
+
+ e.vertices[e.vertices.index(self.vertices[i])] = v
+
+ e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index)
+ self.edges[e.key] = e
+
+ self.vertices[i].faces.remove(f)
+ f.vertices[f.vertices.index(self.vertices[i])] = v
+ v.faces.append(f)
+
+ if progress:
+ progress.set_progress(0.5+i*0.5/len(self.vertices))
+
+ def split_smooth(self, progress = None):
+ self.split_vertices(self.find_smooth_group, progress)
+
+ def split_uv(self, progress = None):
+ self.split_vertices(self.find_uv_group, progress)
+
+ def find_smooth_group(self, vertex, 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 other not in vertex.faces:
+ continue
+
+ if e.smooth:
+ if not other.flag:
+ other.flag = True
+ queue.append(other)
+
+ return queue
+
+ def find_uv_group(self, vertex, face):
+ uv = face.uv[face.vertices.index(vertex)]
+ face.flag = True
+ group = [face]
+ for f in vertex.faces:
+ if not f.flag and f.uv[f.vertices.index(vertex)]==uv:
+ f.flag = True
+ group.append(f)
+ return group
+
+ def compute_normals(self):
+ for v in self.vertices:
+ if v.faces:
+ v.normal = mathutils.Vector()
+ for f in v.faces:
+ v.normal += f.normal
+ v.normal.normalize()
+ else:
+ # XXX Should use edges to compute normal
+ v.normal = mathutils.Vector(0, 0, 1)
+
+ def compute_uv(self):
+ for v in self.vertices:
+ if v.faces:
+ v.uv = v.faces[0].uv[v.faces[0].vertices.index(v)]
+
+ def compute_tbn(self):
+ for v in self.vertices:
+ v.tan = mathutils.Vector()
+ v.bino = mathutils.Vector()
+ for f in v.faces:
+ fv = f.pivot_vertices(False, v)
+ v1 = fv[1]
+ v2 = fv[-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 = fv[1].co-fv[0].co
+ edge2 = fv[-1].co-fv[0].co
+ if div:
+ v.tan += (edge1*dv2-edge2*dv1)/div
+ v.bino += (edge2*du1-edge1*du2)/div
+ if v.tan.length:
+ v.tan.normalize()
+ if v.bino.length:
+ v.bino.normalize()
+
+ def create_strip(self, face, max_len):
+ edge = None
+ for e in face.edges:
+ other = e.other_face(face)
+ if other and not other.flag:
+ edge = e
+ break
+
+ if not edge:
+ return None
+
+ vertices = face.pivot_vertices(*edge.vertices)
+ if len(vertices)==3:
+ result = [vertices[-1], vertices[0]]
+ else:
+ result = [vertices[-2], vertices[-1]]
+
+ while 1:
+ vertices = face.pivot_vertices(*result[-2:])
+ k = len(result)%2
+
+ face.flag = True
+ if len(vertices)==4 and not k:
+ result.append(vertices[3])
+ result.append(vertices[2])
+ if len(vertices)==4 and k:
+ result.append(vertices[3])
+
+ if len(result)>=max_len:
+ break
+
+ edge = face.get_edge(*result[-2:])
+
+ next = edge.other_face(face)
+ if not next or next.flag:
+ break
+ face = next
+
+ return result