]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mesh_mspgl/export_mspgl.py
6de38f8722935d884f45c4fbc441bca1e28926f7
[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.tbn_vecs = False
75                 self.compound = False
76                 self.object = False
77                 self.material_tex = False
78
79         def stripify(self, mesh, progress = None):
80                 for f in mesh.faces:
81                         f.flag = False
82
83                 faces_done = 0
84                 strips = []
85                 loose = []
86
87                 cache = None
88                 if self.optimize_cache:
89                         cache = VertexCache(self.cache_size)
90
91                 island = []
92                 island_strips = []
93                 while 1:
94                         if not island:
95                                 queue = []
96                                 for f in mesh.faces:
97                                         if not f.flag:
98                                                 f.flag = True
99                                                 queue.append(f)
100                                                 break
101
102                                 if not queue:
103                                         break
104
105                                 while queue:
106                                         f = queue[0]
107                                         del queue[0]
108                                         island.append(f)
109
110                                         for e in f.edges:
111                                                 other = e.other_face(f)
112                                                 if other and not other.flag:
113                                                         other.flag = True
114                                                         queue.append(other)
115
116                                 for f in island:
117                                         f.flag = False
118
119                         best = 5
120                         face = None
121                         for f in island:
122                                 if f.flag:
123                                         continue
124                                 score = 0
125                                 for e in f.edges:
126                                         other = e.other_face(f)
127                                         if other and not other.flag:
128                                                 score += 1
129                                 if score>0 and score<best:
130                                         face = f
131                                         best = score
132
133                         if not face:
134                                 while island_strips:
135                                         best = 0
136                                         if cache:
137                                                 best_hits = 0
138                                                 for i in range(len(island_strips)):
139                                                         hits = cache.test_strip(island_strips[i])
140                                                         if hits>best_hits:
141                                                                 best = i
142                                                                 best_hits = hits
143
144                                         s = island_strips[best]
145                                         del island_strips[best]
146                                         strips.append(s)
147
148                                         if cache:
149                                                 cache.fetch_strip(s)
150
151                                 faces_done += len(island)
152                                 if progress:
153                                         progress.set_progress(float(faces_done)/len(mesh.faces))
154
155                                 loose += [f for f in island if not f.flag]
156                                 for f in island:
157                                         f.flag = True
158
159                                 island = []
160                                 island_strips = []
161                                 continue
162
163                         strip = mesh.create_strip(face, self.max_strip_len)
164                         if strip:
165                                 island_strips.append(strip)
166
167                 if cache:
168                         cache = VertexCache(self.cache_size)
169                         total_hits = 0
170
171                 if self.use_degen_tris and strips:
172                         big_strip = []
173
174                         for s in strips:
175                                 if big_strip:
176                                         glue = [big_strip[-1], s[0]]
177                                         if len(big_strip)%2:
178                                                 glue += [s[0]]
179
180                                         big_strip += glue
181                                         if cache:
182                                                 total_hits += cache.fetch_strip(glue)
183
184                                 big_strip += s
185                                 if cache:
186                                         total_hits += cache.fetch_strip(s)
187
188                         for f in loose:
189                                 if len(big_strip)%2:
190                                         order = (-1, -2, 0, 1)
191                                 else:
192                                         order = (0, 1, -1, -2)
193                                 vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
194
195                                 if big_strip:
196                                         glue = [big_strip[-1], vertices[0]]
197                                         big_strip += glue
198                                         if cache:
199                                                 total_hits += cache.fetch_strip(glue)
200
201                                 big_strip += vertices
202                                 if cache:
203                                         total_hits += cache.fetch_strip(vertices)
204
205                         strips = [big_strip]
206                         loose = []
207
208                 return strips, loose
209
210         def export(self, context, fn):
211                 if self.compound:
212                         objs = context.selected_objects
213                 else:
214                         objs = [context.active_object]
215
216                 if not objs:
217                         raise Exception("Nothing to export")
218                 for o in objs:
219                         if o.type!="MESH":
220                                 raise Exception("Can only export Mesh data")
221
222                 from .mesh import Mesh
223                 from .util import Progress
224
225                 progress = Progress()
226                 progress.set_task("Preparing", 0.0, 0.0)
227
228                 mesh = None
229                 bmeshes = []
230                 for o in objs:
231                         bmesh = o.create_mesh(context.scene, True, "PREVIEW")
232                         bmeshes.append(bmesh)
233                         if not mesh:
234                                 mesh = Mesh(bmesh)
235                         else:
236                                 mesh.splice(Mesh(bmesh))
237
238                 progress.set_task("Smoothing", 0.05, 0.35)
239                 mesh.split_smooth()
240
241                 mesh.compute_normals()
242
243                 if self.material_tex:
244                         mesh.generate_material_uv()
245
246                 if mesh.has_uv:
247                         progress.set_task("Splitting UVs", 0.35, 0.65)
248                         mesh.split_uv()
249
250                         mesh.compute_uv()
251                         if self.tbn_vecs:
252                                 mesh.compute_tbn()
253
254                 strips = []
255                 loose = mesh.faces
256                 if self.use_strips:
257                         progress.set_task("Creating strips", 0.65, 0.95)
258                         strips, loose = self.stripify(mesh, progress)
259
260                 progress.set_task("Writing file", 0.95, 1.0)
261
262                 out_file = OutFile(fn)
263                 if self.object:
264                         out_file.begin("mesh")
265
266                 fmt = "NORMAL3"
267                 if mesh.has_uv:
268                         fmt += "_TEXCOORD2"
269                         if self.tbn_vecs:
270                                 fmt += "_ATTRIB33_ATTRIB34"
271                 fmt += "_VERTEX3"
272                 out_file.begin("vertices", fmt)
273                 normal = None
274                 uv = None
275                 tan = None
276                 bino = None
277                 for v in mesh.vertices:
278                         if v.normal!=normal:
279                                 out_file.write("normal3", *v.normal)
280                                 normal = v.normal
281                         if v.uv!=uv:
282                                 out_file.write("texcoord2", *v.uv)
283                                 uv = v.uv
284                         if v.tan!=tan:
285                                 out_file.write("attrib3", 3, *v.tan)
286                                 tan = v.tan
287                         if v.bino!=bino:
288                                 out_file.write("attrib3", 4, *v.bino)
289                                 bino = v.bino
290                         out_file.write("vertex3", *v.co)
291                 out_file.end()
292                 for s in strips:
293                         out_file.begin("batch", "TRIANGLE_STRIP")
294                         indices = []
295                         n = 0
296                         for v in s:
297                                 indices.append(v.index)
298                                 if len(indices)>=32:
299                                         out_file.write("indices", *indices)
300                                         indices = []
301                         if indices:
302                                 out_file.write("indices", *indices)
303                         out_file.end()
304
305                 if loose:
306                         out_file.begin("batch", "TRIANGLES")
307                         for f in loose:
308                                 for i in range(2, len(f.vertices)):
309                                         out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
310                         out_file.end()
311
312                 if self.export_lines and mesh.lines:
313                         out_file.write("batch", "LINES")
314                         for l in mesh.lines:
315                                 out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
316                         out_file.end()
317
318                 if self.object:
319                         out_file.end()
320                         out_file.begin("technique")
321                         out_file.begin("pass", '""')
322                         if self.material_tex:
323                                 out_file.begin("material")
324                                 out_file.write("diffuse", 1.0, 1.0, 1.0, 1.0)
325                                 out_file.end()
326                                 out_file.begin("texunit", 0)
327                                 out_file.begin("texture2d")
328                                 out_file.write("min_filter", "NEAREST")
329                                 out_file.write("mag_filter", "NEAREST")
330                                 out_file.write("storage", "RGB", len(mesh.materials), 1)
331                                 texdata = '"'
332                                 for m in mesh.materials:
333                                         color = [int(c*255) for c in m.diffuse_color]
334                                         texdata += "\\x%02X\\x%02X\\x%02X"%tuple(color)
335                                 texdata += '"'
336                                 out_file.write("raw_data", texdata)
337                                 out_file.end()
338                                 out_file.end()
339                         elif mesh.materials:
340                                 m = mesh.materials[0]
341                                 out_file.begin("material")
342                                 out_file.write("diffuse", m.R, m.G, m.B, 1.0)
343                                 out_file.write("ambient", m.R*m.amb, m.G*m.amb, m.B*m.amb, 1.0)
344                                 out_file.write("specular", m.specR*m.spec, m.specG*m.spec, m.specB*m.spec, 1.0)
345                                 out_file.write("shininess", m.hard);
346                                 out_file.end()
347                         out_file.end()
348                         out_file.end()
349
350                 progress.set_task("Done", 1.0, 1.0)
351
352                 for m in bmeshes:
353                         bpy.data.meshes.remove(m)