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