]> git.tdb.fi Git - libs/gl.git/blob - mesh_export.py
Blender exporter: Add support for texture coordinates
[libs/gl.git] / mesh_export.py
1 #!BPY
2 # $Id$
3
4 """
5 Name: 'MSP GL Mesh (.mesh)...'
6 Blender: 244
7 Group: 'Export'
8 """
9
10 import sys
11 import math
12 import bpy
13 import Blender
14
15 class Edge:
16         def __init__(self, me):
17                 if me.__class__==Edge:
18                         self._medge=me._medge
19                         self.smooth=me.smooth
20                 else:
21                         self._medge=me
22                         self.smooth=False
23                 self.faces=[]
24
25         def __getattr__(self, attr):
26                 return getattr(self._medge, attr)
27
28         def check_smooth(self, limit):
29                 if len(self.faces)!=2:
30                         return
31
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:
34                         self.smooth=1
35
36         def other_face(self, f):
37                 if f.index==self.faces[0].index:
38                         if len(self.faces)>=2:
39                                 return self.faces[1]
40                         else:
41                                 return None
42                 else:
43                         return self.faces[0]
44
45
46 class Vertex:
47         def __init__(self, mv):
48                 if mv.__class__==Vertex:
49                         self._mvert=mv._mvert
50                         self.uv=mv.uv
51                 else:
52                         self._mvert=mv
53                         self.uv=None
54                 self.orig_index=self._mvert.index
55
56         def __getattr__(self, attr):
57                 return getattr(self._mvert, attr)
58
59
60 class Face:
61         def __init__(self, mf):
62                 self._mface=mf
63                 self.smooth_group=None
64                 self.edges=[]
65                 self.verts=[v for v in mf.verts]
66                 self.flag=False
67
68         def __getattr__(self, attr):
69                 return getattr(self._mface, attr)
70
71         def get_vertices_from(self, *vt):
72                 indices=[u.index for u in vt]
73                 flags=[(v.index in indices) for v in self.verts]
74                 l=len(self.verts)
75                 for i in range(l):
76                         if flags[i] and not flags[(i+l-1)%l]:
77                                 return self.verts[i:]+self.verts[:i]
78
79
80 class SmoothGroup:
81         def __init__(self, index):
82                 self.index=index
83                 self.faces=[]
84                 self.verts=[]
85
86         def find_vertices(self):
87                 vert_map={}
88                 for f in self.faces:
89                         for i in range(len(f.verts)):
90                                 v=f.verts[i]
91                                 if v.index not in vert_map:
92                                         vt=Vertex(v)
93                                         vt.index=len(self.verts)
94                                         self.verts.append(vt)
95
96                                         vert_map[v.index]=vt
97                                         vt.no=Blender.Mathutils.Vector(f.no)
98                                 else:
99                                         vt=vert_map[v.index]
100                                         vt.no+=f.no
101                                 f.verts[i]=vt
102
103                 for v in self.verts:
104                         v.no.normalize()
105
106         def separate_uv(self):
107                 copies={}
108                 for f in self.faces:
109                         for i in range(len(f.verts)):
110                                 v=f.verts[i]
111                                 if not v.uv:
112                                         v.uv=f.uv[i]
113                                 elif f.uv[i]!=v.uv:
114                                         if v.index not in copies:
115                                                 copies[v.index]=[]
116
117                                         vt=None
118                                         for w in copies[v.index]:
119                                                 if w.uv==f.uv[i]:
120                                                         vt=w
121                                                         break
122
123                                         if not vt:
124                                                 vt=Vertex(v)
125                                                 vt.index=len(self.verts)
126                                                 vt.uv=f.uv[i]
127                                                 self.verts.append(vt)
128                                                 copies[v.index].append(vt)
129
130                                         f.verts[i]=vt
131
132         def create_edges(self):
133                 edge_map={}
134                 for f in self.faces:
135                         vert_map=dict([(v.orig_index, v) for v in f.verts])
136                         for i in range(len(f.edges)):
137                                 v1=vert_map[f.edges[i].v1.index]
138                                 v2=vert_map[f.edges[i].v2.index]
139                                 key=tuple(sorted((v1.index, v2.index)))
140
141                                 if key in edge_map:
142                                         e=edge_map[key]
143                                 else:
144                                         e=Edge(f.edges[i])
145                                         edge_map[key]=e
146                                         e.v1=v1
147                                         e.v2=v2
148                                         e.key=key
149
150                                 f.edges[i]=e
151                                 e.faces.append(f)
152
153
154 class Exporter:
155         def __init__(self, fn):
156                 self.filename=fn
157                 if fn==None:
158                         self.out_file=sys.stdout
159                 else:
160                         self.out_file=file(fn, "w")
161                 self.use_strips=True
162                 self.use_degen_tris=True
163                 self.debug=False
164
165         def find_smooth_group(self, face, sg):
166                 face.smooth_group=sg
167                 sg.faces.append(face)
168                 queue=[face]
169                 while queue:
170                         cur=queue.pop(0)
171                         for e in cur.edges:
172                                 if e.smooth:
173                                         other=e.other_face(cur)
174                                         if other and not other.smooth_group:
175                                                 other.smooth_group=sg
176                                                 sg.faces.append(other)
177                                                 queue.append(other)
178
179         def create_strip(self, face):
180                 edge=None
181                 for e in face.edges:
182                         other=e.other_face(face)
183                         if other and other.smooth_group.index==face.smooth_group.index and not other.flag:
184                                 edge=e
185                                 break
186
187                 if not edge:
188                         return None
189
190                 if self.debug:
191                         print "Starting strip from %s"%[v.index for v in face.verts]
192
193                 verts=face.get_vertices_from(edge.v1, edge.v2)
194                 result=[verts[-2], verts[-1]]
195
196                 while 1:
197                         verts=face.get_vertices_from(*result[-2:])
198                         k=len(result)%2
199                         if self.debug:
200                                 print "  %d %s"%(len(result), [v.index for v in verts])
201
202                         face.flag=True
203                         if len(verts)==4 and not k:
204                                 result.append(verts[3])
205                         result.append(verts[2])
206                         if len(verts)==4 and k:
207                                 result.append(verts[3])
208
209                         i1=result[-2].index
210                         i2=result[-1].index
211                         ekey=(min(i1, i2), max(i1, i2))
212                         for e in face.edges:
213                                 if e.key==ekey:
214                                         edge=e
215                                         break
216
217                         next=edge.other_face(face)
218                         if not next or next.smooth_group.index!=face.smooth_group.index or next.flag:
219                                 break
220                         face=next
221
222                 if self.debug:
223                         print "  %s"%[v.index for v in result]
224
225                 return result
226
227         def export(self):
228                 scene=bpy.data.scenes.active
229
230                 obj=scene.objects.active
231                 if obj.getType()!="Mesh":
232                         raise Exception, "Can only export Mesh data"
233
234                 mesh=obj.getData(mesh=True)
235
236                 faces=[Face(f) for f in mesh.faces]
237
238                 edges=dict([(e.key, Edge(e)) for e in mesh.edges])
239                 for f in faces:
240                         for e in f.edge_keys:
241                                 edges[e].faces.append(f)
242                                 f.edges.append(edges[e])
243
244                 smooth_limit=math.cos(mesh.degr*math.pi/180)
245                 for e in edges.itervalues():
246                         e.check_smooth(smooth_limit)
247
248                 if self.debug:
249                         print "%d faces, %d edges"%(len(faces), len(edges))
250
251                 smooth_groups=[]
252                 for f in faces:
253                         if not f.smooth_group:
254                                 sg=SmoothGroup(len(smooth_groups))
255                                 smooth_groups.append(sg)
256                                 self.find_smooth_group(f, sg)
257
258                 for sg in smooth_groups:
259                         sg.find_vertices()
260                         if mesh.faceUV:
261                                 sg.separate_uv()
262                         sg.create_edges()
263
264                 verts=[]
265                 for sg in smooth_groups:
266                         for v in sg.verts:
267                                 v.index=len(verts)
268                                 verts.append(v)
269
270                 if self.debug:
271                         print "%d smooth groups:"%(len(smooth_groups))
272                         for i in range(len(smooth_groups)):
273                                 sg=smooth_groups[i]
274                                 print "  %d: %d faces, %d vertices"%(i, len(sg.faces), len(sg.verts))
275
276                 strips=[]
277                 if self.use_strips:
278                         for sg in smooth_groups:
279                                 for f in sg.faces:
280                                         if not f.flag:
281                                                 strip=self.create_strip(f)
282                                                 if strip:
283                                                         strips.append(strip)
284
285                         if self.use_degen_tris:
286                                 big_strip=[]
287                                 for s in strips:
288                                         if big_strip:
289                                                 big_strip+=[big_strip[-1], s[0]]
290                                         big_strip+=s
291
292                                 for f in faces:
293                                         if not f.flag:
294                                                 if big_strip:
295                                                         big_strip+=[big_strip[-1], f.verts[0]]
296                                                 big_strip+=[f.verts[i] for i in (0, 1, -1)]
297                                                 if len(f.verts)==4:
298                                                         big_strip.append(f.verts[-2])
299                                                 f.flag=True
300
301                                 strips=[big_strip]
302
303                 self.out_file.write("vertices NORMAL3")
304                 if mesh.faceUV:
305                         self.out_file.write("_TEXCOORD2")
306                 self.out_file.write("_VERTEX3\n{\n")
307                 norm=None
308                 uv=None
309                 for v in verts:
310                         if v.no!=norm:
311                                 self.out_file.write("\tnormal3 %f %f %f;\n"%tuple(v.no))
312                                 norm=v.no
313                         if v.uv!=uv:
314                                 self.out_file.write("\ttexcoord2 %f %f;\n"%tuple(v.uv))
315                                 uv=v.uv
316                         self.out_file.write("\tvertex3 %f %f %f;\n"%tuple(v.co))
317                 self.out_file.write("};\n")
318                 for s in strips:
319                         self.out_file.write("batch TRIANGLE_STRIP\n{\n\tindices")
320                         n=0
321                         for v in s:
322                                 self.out_file.write(" %u"%v.index)
323                                 n+=1;
324                                 if n%32==0:
325                                         self.out_file.write(";\n\tindices")
326                         self.out_file.write(";\n};\n")
327
328                 first=True
329                 for f in faces:
330                         if not f.flag:
331                                 if first:
332                                         self.out_file.write("batch TRIANGLES\n{\n")
333                                         first=False
334                                 for i in range(2, len(f.verts)):
335                                         self.out_file.write("\tindices %u %u %u;\n"%(f.verts[0].index, f.verts[i-1].index, f.verts[i].index))
336                 if not first:
337                         self.out_file.write("};\n")
338
339
340 class FrontEnd:
341         def run(self):
342                 #self.export(None)
343                 Blender.Window.FileSelector(self.export, "Export MSP GL mesh", Blender.sys.makename(ext='.mesh'))
344
345         def export(self, fn):
346                 exp=Exporter(fn)
347                 #exp.use_degen_tris=False
348                 #exp.debug=True
349                 exp.export()
350
351
352 if __name__=="__main__":
353         fe=FrontEnd()
354         fe.run()