]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mesh_mspgl/export_mspgl.py
d54d1e38478a860c5b4619deb9d8505813f3c53f
[libs/gl.git] / blender / io_mesh_mspgl / export_mspgl.py
1 # $Id: mesh_export.py 137 2010-12-05 19:22:35Z tdb $
2
3 import bpy
4
5 class VertexCache:
6         def __init__(self, size):
7                 self.size = size
8                 self.slots = [-1]*self.size
9
10         def fetch(self, v):
11                 hit = v.index in self.slots
12                 if hit:
13                         self.slots.remove(v.index)
14                 self.slots.append(v.index)
15                 if not hit:
16                         del self.slots[0]
17                 return hit
18
19         def fetch_strip(self, strip):
20                 hits = 0
21                 for v in strip:
22                         if self.fetch(v):
23                                 hits += 1
24                 return hits
25
26         def test_strip(self, strip):
27                 hits = 0
28                 for i in range(len(strip)):
29                         if i>=self.size:
30                                 break
31                         if strip[i].index in self.slots[i:]:
32                                 hits += 1
33                 return hits
34
35
36 class OutFile:
37         def __init__(self, fn):
38                 if fn==None:
39                         self.file = sys.stdout
40                 else:
41                         self.file = open(fn, "w")
42                 self.indent = 0
43
44         def make(self, kwd, *params):
45                 pstr = ""
46                 for p in params:
47                         if type(p)==float:
48                                 pstr += " %.6g"%p
49                         else:
50                                 pstr += " %s"%p
51                 return "%s%s"%(kwd, pstr)
52
53         def write(self, kwd, *params):
54                 self.file.write("%s%s;\n"%('\t'*self.indent, self.make(kwd, *params)))
55
56         def begin(self, kwd, *params):
57                 i = '\t'*self.indent
58                 self.file.write("%s%s\n%s{\n"%(i, self.make(kwd, *params), i))
59                 self.indent += 1
60
61         def end(self):
62                 self.indent -= 1
63                 self.file.write("%s};\n"%('\t'*self.indent))
64
65
66 class Exporter:
67         def __init__(self):
68                 self.use_strips = True
69                 self.use_degen_tris = True
70                 self.max_strip_len = 1024
71                 self.optimize_cache = False
72                 self.cache_size = 64
73                 self.export_lines = True
74                 self.export_uv = "UNIT0"
75                 self.tbn_vecs = False
76                 self.tbn_uvtex = ""
77                 self.compound = False
78                 self.object = False
79                 self.material_tex = False
80                 self.smoothing = "MSPGL"
81
82         def stripify(self, mesh, progress = None):
83                 for f in mesh.faces:
84                         f.flag = False
85
86                 faces_done = 0
87                 strips = []
88                 loose = []
89
90                 cache = None
91                 if self.optimize_cache:
92                         cache = VertexCache(self.cache_size)
93
94                 island = []
95                 island_strips = []
96                 while 1:
97                         if not island:
98                                 queue = []
99                                 for f in mesh.faces:
100                                         if not f.flag:
101                                                 f.flag = True
102                                                 queue.append(f)
103                                                 break
104
105                                 if not queue:
106                                         break
107
108                                 while queue:
109                                         f = queue[0]
110                                         del queue[0]
111                                         island.append(f)
112
113                                         for e in f.edges:
114                                                 other = e.other_face(f)
115                                                 if other and not other.flag:
116                                                         other.flag = True
117                                                         queue.append(other)
118
119                                 for f in island:
120                                         f.flag = False
121
122                         best = 5
123                         face = None
124                         for f in island:
125                                 if f.flag:
126                                         continue
127                                 score = 0
128                                 for e in f.edges:
129                                         other = e.other_face(f)
130                                         if other and not other.flag:
131                                                 score += 1
132                                 if score>0 and score<best:
133                                         face = f
134                                         best = score
135
136                         if not face:
137                                 while island_strips:
138                                         best = 0
139                                         if cache:
140                                                 best_hits = 0
141                                                 for i in range(len(island_strips)):
142                                                         hits = cache.test_strip(island_strips[i])
143                                                         if hits>best_hits:
144                                                                 best = i
145                                                                 best_hits = hits
146
147                                         s = island_strips[best]
148                                         del island_strips[best]
149                                         strips.append(s)
150
151                                         if cache:
152                                                 cache.fetch_strip(s)
153
154                                 faces_done += len(island)
155                                 if progress:
156                                         progress.set_progress(float(faces_done)/len(mesh.faces))
157
158                                 loose += [f for f in island if not f.flag]
159                                 for f in island:
160                                         f.flag = True
161
162                                 island = []
163                                 island_strips = []
164                                 continue
165
166                         strip = mesh.create_strip(face, self.max_strip_len)
167                         if strip:
168                                 island_strips.append(strip)
169
170                 if cache:
171                         cache = VertexCache(self.cache_size)
172                         total_hits = 0
173
174                 if self.use_degen_tris and strips:
175                         big_strip = []
176
177                         for s in strips:
178                                 if big_strip:
179                                         glue = [big_strip[-1], s[0]]
180                                         if len(big_strip)%2:
181                                                 glue += [s[0]]
182
183                                         big_strip += glue
184                                         if cache:
185                                                 total_hits += cache.fetch_strip(glue)
186
187                                 big_strip += s
188                                 if cache:
189                                         total_hits += cache.fetch_strip(s)
190
191                         for f in loose:
192                                 if len(big_strip)%2:
193                                         order = (-1, -2, 0, 1)
194                                 else:
195                                         order = (0, 1, -1, -2)
196                                 vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
197
198                                 if big_strip:
199                                         glue = [big_strip[-1], vertices[0]]
200                                         big_strip += glue
201                                         if cache:
202                                                 total_hits += cache.fetch_strip(glue)
203
204                                 big_strip += vertices
205                                 if cache:
206                                         total_hits += cache.fetch_strip(vertices)
207
208                         strips = [big_strip]
209                         loose = []
210
211                 return strips, loose
212
213         def export(self, context, fn):
214                 if self.compound:
215                         objs = context.selected_objects
216                 else:
217                         objs = [context.active_object]
218
219                 if not objs:
220                         raise Exception("Nothing to export")
221                 for o in objs:
222                         if o.type!="MESH":
223                                 raise Exception("Can only export Mesh data")
224
225                 from .mesh import Mesh
226                 from .util import Progress
227
228                 progress = Progress()
229                 progress.set_task("Preparing", 0.0, 0.0)
230
231                 mesh = None
232                 bmeshes = []
233                 for o in objs:
234                         bmesh = o.create_mesh(context.scene, True, "PREVIEW")
235                         bmeshes.append(bmesh)
236                         if not mesh:
237                                 mesh = Mesh(bmesh)
238                         else:
239                                 mesh.splice(Mesh(bmesh))
240
241                 progress.set_task("Smoothing", 0.05, 0.35)
242                 if self.smoothing=="NONE":
243                         mesh.flatten_faces()
244                 mesh.split_smooth(progress)
245
246                 if self.smoothing!="BLENDER":
247                         mesh.compute_normals()
248
249                 if self.material_tex:
250                         mesh.generate_material_uv()
251
252                 texunits = []
253                 if mesh.uv_textures and self.export_uv!="NONE":
254                         if self.export_uv=="UNIT0":
255                                 texunits = [0]
256                         else:
257                                 texunits = list(range(len(mesh.uv_textures)))
258
259                         tbn_unit = 0
260                         if self.tbn_vecs:
261                                 uvtex_names = [u.name for u in mesh.uv_textures]
262                                 if self.tbn_uvtex in uvtex_names:
263                                         tbn_unit = uvtex_names.index(uvtex)
264                                         del texunits[tbn_unit]
265                                         texunits.insert(0, tbn_unit)
266
267                         for i in texunits:
268                                 progress.set_task("Splitting UVs", 0.35+0.3*i/len(texunits), 0.35+0.3*(i+1)/len(texunits))
269                                 mesh.split_uv(i, progress)
270                                 if self.tbn_vecs and i==tbn_unit:
271                                         mesh.compute_uv()
272                                         mesh.compute_tbn(i)
273
274                         mesh.compute_uv()
275
276                 strips = []
277                 loose = mesh.faces
278                 if self.use_strips:
279                         progress.set_task("Creating strips", 0.65, 0.95)
280                         strips, loose = self.stripify(mesh, progress)
281
282                 progress.set_task("Writing file", 0.95, 1.0)
283
284                 out_file = OutFile(fn)
285                 if self.object:
286                         out_file.begin("mesh")
287
288                 fmt = "NORMAL3"
289                 if texunits:
290                         fmt += "_TEXCOORD2"
291                         for i in texunits[1:]:
292                                 fmt += "_TEXCOORD2%d"%i
293                         if self.tbn_vecs:
294                                 fmt += "_ATTRIB33_ATTRIB34"
295                 fmt += "_VERTEX3"
296                 out_file.begin("vertices", fmt)
297                 normal = None
298                 uvs = [None]*len(mesh.uv_textures)
299                 tan = None
300                 bino = None
301                 for v in mesh.vertices:
302                         if v.normal!=normal:
303                                 out_file.write("normal3", *v.normal)
304                                 normal = v.normal
305                         for i in texunits:
306                                 if v.uvs[i]!=uvs[i]:
307                                         if i==0:
308                                                 out_file.write("texcoord2", *v.uvs[i])
309                                         else:
310                                                 out_file.write("multitexcoord2", i, *v.uvs[i])
311                                         uvs[i] = v.uvs[i]
312                         if v.tan!=tan:
313                                 out_file.write("attrib3", 3, *v.tan)
314                                 tan = v.tan
315                         if v.bino!=bino:
316                                 out_file.write("attrib3", 4, *v.bino)
317                                 bino = v.bino
318                         out_file.write("vertex3", *v.co)
319                 out_file.end()
320                 for s in strips:
321                         out_file.begin("batch", "TRIANGLE_STRIP")
322                         indices = []
323                         n = 0
324                         for v in s:
325                                 indices.append(v.index)
326                                 if len(indices)>=32:
327                                         out_file.write("indices", *indices)
328                                         indices = []
329                         if indices:
330                                 out_file.write("indices", *indices)
331                         out_file.end()
332
333                 if loose:
334                         out_file.begin("batch", "TRIANGLES")
335                         for f in loose:
336                                 for i in range(2, len(f.vertices)):
337                                         out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
338                         out_file.end()
339
340                 if self.export_lines and mesh.lines:
341                         out_file.write("batch", "LINES")
342                         for l in mesh.lines:
343                                 out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
344                         out_file.end()
345
346                 if self.object:
347                         out_file.end()
348                         out_file.begin("technique")
349                         out_file.begin("pass", '""')
350                         if self.material_tex:
351                                 out_file.begin("material")
352                                 out_file.write("diffuse", 1.0, 1.0, 1.0, 1.0)
353                                 out_file.end()
354                                 out_file.begin("texunit", 0)
355                                 out_file.begin("texture2d")
356                                 out_file.write("min_filter", "NEAREST")
357                                 out_file.write("mag_filter", "NEAREST")
358                                 out_file.write("storage", "RGB", len(mesh.materials), 1)
359                                 texdata = '"'
360                                 for m in mesh.materials:
361                                         color = [int(c*255) for c in m.diffuse_color]
362                                         texdata += "\\x%02X\\x%02X\\x%02X"%tuple(color)
363                                 texdata += '"'
364                                 out_file.write("raw_data", texdata)
365                                 out_file.end()
366                                 out_file.end()
367                         elif mesh.materials:
368                                 m = mesh.materials[0]
369                                 out_file.begin("material")
370                                 out_file.write("diffuse", m.R, m.G, m.B, 1.0)
371                                 out_file.write("ambient", m.R*m.amb, m.G*m.amb, m.B*m.amb, 1.0)
372                                 out_file.write("specular", m.specR*m.spec, m.specG*m.spec, m.specB*m.spec, 1.0)
373                                 out_file.write("shininess", m.hard);
374                                 out_file.end()
375                         out_file.end()
376                         out_file.end()
377
378                 progress.set_task("Done", 1.0, 1.0)
379
380                 for m in bmeshes:
381                         bpy.data.meshes.remove(m)