]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mesh_mspgl/mesh.py
5af8578720d10bbe78759f995d72ab6912b79311
[libs/gl.git] / blender / io_mesh_mspgl / mesh.py
1 import math
2 import mathutils
3
4 def make_edge_key(i1, i2):
5         return (min(i1, i2), max(i1, i2))
6
7 class Edge:
8         def __init__(self, me):
9                 if me.__class__==Edge:
10                         self._medge = me._medge
11                         self.vertices = me.vertices[:]
12                         self.smooth = me.smooth
13                 else:
14                         self._medge = me
15                         self.smooth = False
16                 self.faces = []
17
18         def __getattr__(self, attr):
19                 return getattr(self._medge, attr)
20
21         def check_smooth(self, limit):
22                 if len(self.faces)!=2:
23                         return
24
25                 d = self.faces[0].normal.dot(self.faces[1].normal)
26                 if (d>limit and self.faces[0].use_smooth and self.faces[1].use_smooth) or d>0.999:
27                         self.smooth = True
28
29         def other_face(self, f):
30                 if f.index==self.faces[0].index:
31                         if len(self.faces)>=2:
32                                 return self.faces[1]
33                         else:
34                                 return None
35                 else:
36                         return self.faces[0]
37
38
39 class Vertex:
40         def __init__(self, mv):
41                 if mv.__class__==Vertex:
42                         self._mvert = mv._mvert
43                         self.normal = mv.normal
44                         self.uv = mv.uv
45                 else:
46                         self._mvert = mv
47                         self.uv = None
48                 self.flag = False
49                 self.faces = []
50                 self.tan = None
51                 self.bino = None
52
53         def __getattr__(self, attr):
54                 return getattr(self._mvert, attr)
55
56         def __cmp__(self, other):
57                 if other is None:
58                         return 1
59                 return cmp(self.index, other.index)
60
61
62 class Face:
63         def __init__(self, mf):
64                 self._mface = mf
65                 self.edges = []
66                 self.vertices = mf.vertices[:]
67                 self.uv = None
68                 self.flag = False
69                 self.material = None
70
71         def __getattr__(self, attr):
72                 return getattr(self._mface, attr)
73
74         def __cmp__(self, other):
75                 if other is None:
76                         return 1
77                 return cmp(self.index, other.index)
78
79         def pivot_vertices(self, *vt):
80                 flags = [(v in vt) for v in self.vertices]
81                 l = len(self.vertices)
82                 for i in range(l):
83                         if flags[i] and not flags[(i+l-1)%l]:
84                                 return self.vertices[i:]+self.vertices[:i]
85
86         def get_edge(self, v1, v2):     
87                 key = make_edge_key(v1.index, v2.index)
88                 for e in self.edges:
89                         if e.key==key:
90                                 return e
91                 raise KeyError("No edge %s"%(key,))
92
93
94 class Line:
95         def __init__(self, e):
96                 self.edge = e
97                 self.vertices = e.vertices[:]
98                 self.flag = False
99
100
101 class Mesh:
102         def __init__(self, m):
103                 self._mesh = m
104                 self.vertices = [Vertex(v) for v in m.vertices]
105                 self.faces = [Face(f) for f in m.faces]
106                 self.materials = m.materials[:]
107                 self.has_uv = False
108
109                 uvtex = None
110                 if m.uv_textures:
111                         uvtex = self.uv_textures[0]
112                         self.has_uv = True
113
114                 for f in self.faces:
115                         f.vertices = [self.vertices[i] for i in f.vertices]
116                         if uvtex:
117                                 f.uv = uvtex.data[f.index].uv
118                         for v in f.vertices:
119                                 v.faces.append(f)
120
121                 self.edges = dict([(e.key, Edge(e)) for e in m.edges])
122                 for f in self.faces:
123                         for k in f.edge_keys:
124                                 e = self.edges[k]
125                                 e.faces.append(self.faces[f.index])
126                                 f.edges.append(e)
127
128                 self.lines = [Line(e) for e in self.edges.values() if not e.faces]
129
130                 if m.use_auto_smooth:
131                         smooth_limit = math.cos(m.auto_smooth_angle*math.pi/180)
132                 else:
133                         smooth_limit = -1
134
135                 for e in self.edges.values():
136                         e.vertices = [self.vertices[i] for i in e.vertices]
137                         e.check_smooth(smooth_limit)
138
139         def __getattr__(self, attr):
140                 return getattr(self._mesh, attr)
141
142         def splice(self, other):
143                 material_map = []
144                 for m in other.materials:
145                         if m in self.materials:
146                                 material_map.append(self.materials.index(m))
147                         else:
148                                 material_map.append(len(self.materials))
149                                 self.materials.append(m)
150
151                 offset = len(self.vertices)
152                 for v in other.vertices:
153                         v.index += offset
154                         self.vertices.append(v)
155
156                 offset = len(self.faces)
157                 for f in other.faces:
158                         f.index += offset
159                         f.material = material_map[f.material_index]
160                         self.faces.append(f)
161
162                 for e in other.edges.values():
163                         e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index)
164                         self.edges[e.key] = e
165
166                 self.lines += other.lines
167         
168         def generate_material_uv(self):
169                 for f in self.faces:
170                         f.uv = ([(f.material_index+0.5)/len(self.materials), 0.5],)*len(f.vertices)
171                 self.has_uv = True
172
173         def split_vertices(self, find_group_func, progress = None):
174                 groups = []
175                 for i in range(len(self.vertices)):
176                         v = self.vertices[i]
177                         for f in v.faces:
178                                 f.flag = False
179
180                         vg = []
181                         for f in v.faces:
182                                 if not f.flag:
183                                         vg.append(find_group_func(v, f))
184
185                         groups.append(vg)
186
187                         if progress:
188                                 progress.set_progress(i*0.5/len(self.vertices))
189
190                 for i in range(len(self.vertices)):
191                         if len(groups[i])==1:
192                                 continue
193
194                         for g in groups[i][1:]:
195                                 v = Vertex(self.vertices[i])
196                                 v.index = len(self.vertices)
197                                 self.vertices.append(v)
198
199                                 for f in g:
200                                         for j in range(len(f.edges)):
201                                                 e = f.edges[j]
202
203                                                 if self.vertices[i] not in e.vertices:
204                                                         continue
205
206                                                 if e.other_face(f) not in g and len(e.faces)>=2:
207                                                         k = e.faces.index(f)
208                                                         e.faces.remove(f)
209                                                         e = Edge(e)
210                                                         f.edges[j] = e
211                                                         e.faces.append(f)
212                                                 else:
213                                                         del self.edges[e.key]
214
215                                                 e.vertices[e.vertices.index(self.vertices[i])] = v
216
217                                                 e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index)
218                                                 self.edges[e.key] = e
219
220                                         self.vertices[i].faces.remove(f)
221                                         f.vertices[f.vertices.index(self.vertices[i])] = v
222                                         v.faces.append(f)
223
224                         if progress:
225                                 progress.set_progress(0.5+i*0.5/len(self.vertices))
226
227         def split_smooth(self, progress = None):
228                 self.split_vertices(self.find_smooth_group, progress)
229
230         def split_uv(self, progress = None):
231                 self.split_vertices(self.find_uv_group, progress)
232
233         def find_smooth_group(self, vertex, face):
234                 face.flag = True
235                 queue = [face]
236
237                 for f in queue:
238                         for e in f.edges:
239                                 other = e.other_face(f)
240                                 #if not other or other.index not in face_indices:
241                                 if other not in vertex.faces:
242                                         continue
243
244                                 if e.smooth:
245                                         if not other.flag:
246                                                 other.flag = True
247                                                 queue.append(other)
248
249                 return queue
250
251         def find_uv_group(self, vertex, face):
252                 uv = face.uv[face.vertices.index(vertex)]
253                 face.flag = True
254                 group = [face]
255                 for f in vertex.faces:
256                         if not f.flag and f.uv[f.vertices.index(vertex)]==uv:
257                                 f.flag = True
258                                 group.append(f)
259                 return group
260
261         def compute_normals(self):
262                 for v in self.vertices:
263                         if v.faces:
264                                 v.normal = mathutils.Vector()
265                                 for f in v.faces:
266                                         v.normal += f.normal
267                                 v.normal.normalize()
268                         else:
269                                 # XXX Should use edges to compute normal
270                                 v.normal = mathutils.Vector(0, 0, 1)
271
272         def compute_uv(self):
273                 for v in self.vertices:
274                         if v.faces:
275                                 v.uv = v.faces[0].uv[v.faces[0].vertices.index(v)]
276
277         def compute_tbn(self):
278                 for v in self.vertices:
279                         v.tan = mathutils.Vector()
280                         v.bino = mathutils.Vector()
281                         for f in v.faces:
282                                 fv = f.pivot_vertices(False, v)
283                                 v1 = fv[1]
284                                 v2 = fv[-1]
285                                 du1 = v1.uv[0]-v.uv[0]
286                                 du2 = v2.uv[0]-v.uv[0]
287                                 dv1 = v1.uv[1]-v.uv[1]
288                                 dv2 = v2.uv[1]-v.uv[1]
289                                 div = du1*dv2-du2*dv1
290                                 edge1 = fv[1].co-fv[0].co
291                                 edge2 = fv[-1].co-fv[0].co
292                                 if div:
293                                         v.tan += (edge1*dv2-edge2*dv1)/div
294                                         v.bino += (edge2*du1-edge1*du2)/div
295                         if v.tan.length:
296                                 v.tan.normalize()
297                         if v.bino.length:
298                                 v.bino.normalize()
299
300         def create_strip(self, face, max_len):
301                 edge = None
302                 for e in face.edges:
303                         other = e.other_face(face)
304                         if other and not other.flag:
305                                 edge = e
306                                 break
307
308                 if not edge:
309                         return None
310
311                 vertices = face.pivot_vertices(*edge.vertices)
312                 if len(vertices)==3:
313                         result = [vertices[-1], vertices[0]]
314                 else:
315                         result = [vertices[-2], vertices[-1]]
316
317                 while 1:
318                         vertices = face.pivot_vertices(*result[-2:])
319                         k = len(result)%2
320
321                         face.flag = True
322                         if len(vertices)==4 and not k:
323                                 result.append(vertices[3])
324                         result.append(vertices[2])
325                         if len(vertices)==4 and k:
326                                 result.append(vertices[3])
327
328                         if len(result)>=max_len:
329                                 break
330
331                         edge = face.get_edge(*result[-2:])
332
333                         next = edge.other_face(face)
334                         if not next or next.flag:
335                                 break
336                         face = next
337
338                 return result