4 def __init__(self, size):
6 self.slots = [-1]*self.size
9 hit = v.index in self.slots
11 self.slots.remove(v.index)
12 self.slots.append(v.index)
17 def fetch_strip(self, strip):
24 def test_strip(self, strip):
26 for i in range(len(strip)):
29 if strip[i].index in self.slots[i:]:
35 def __init__(self, fn):
37 self.file = sys.stdout
39 self.file = open(fn, "w")
42 def make(self, kwd, *params):
49 return "%s%s"%(kwd, pstr)
51 def write(self, kwd, *params):
52 self.file.write("%s%s;\n"%('\t'*self.indent, self.make(kwd, *params)))
54 def begin(self, kwd, *params):
56 self.file.write("%s%s\n%s{\n"%(i, self.make(kwd, *params), i))
61 self.file.write("%s};\n"%('\t'*self.indent))
66 self.use_strips = True
67 self.use_degen_tris = True
68 self.max_strip_len = 1024
69 self.optimize_cache = False
71 self.export_lines = True
72 self.export_uv = "UNIT0"
77 self.material_tex = False
79 self.smoothing = "MSPGL"
81 def stripify(self, mesh, progress = None):
90 if self.optimize_cache:
91 cache = VertexCache(self.cache_size)
97 # No current island; find any unused face to start from
108 # Find all faces connected to the first one
113 for n in f.get_neighbors():
117 # Unflag the island for the next phase
121 # Find an unused face with as few unused neighbors as possible, but
122 # at least one. This heuristic gives a preference to faces in corners
123 # or along borders of a non-closed island.
130 score = sum(n.flag for n in f.get_neighbors())
131 if score>0 and score<best:
136 # Create a strip starting from the face. This will flag the faces.
137 strip = mesh.create_strip(face, self.max_strip_len)
139 island_strips.append(strip)
141 # Couldn't find a candidate face for starting a strip, so we're
142 # done with this island
146 # Find the strip that benefits the most from the current
147 # contents of the vertex cache
149 for i in range(len(island_strips)):
150 hits = cache.test_strip(island_strips[i])
155 strip = island_strips.pop(best)
159 cache.fetch_strip(strip)
161 faces_done += len(island)
163 progress.set_progress(float(faces_done)/len(mesh.faces))
165 # Collect any faces that weren't used in strips
166 loose += [f for f in island if not f.flag]
174 cache = VertexCache(self.cache_size)
177 if self.use_degen_tris and strips:
182 # Generate glue elements, ensuring that the next strip begins at
184 glue = [big_strip[-1], s[0]]
190 total_hits += cache.fetch_strip(glue)
194 total_hits += cache.fetch_strip(s)
197 # Add loose faces to the end. This wastes space, using five
198 # elements per triangle and six elements per quad.
200 order = (-1, -2, 0, 1)
202 order = (0, 1, -1, -2)
203 vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
206 glue = [big_strip[-1], vertices[0]]
209 total_hits += cache.fetch_strip(glue)
211 big_strip += vertices
213 total_hits += cache.fetch_strip(vertices)
220 def export(self, context, fn):
222 objs = context.selected_objects
224 objs = [context.active_object]
227 raise Exception("Nothing to export")
230 raise Exception("Can only export Mesh data")
232 from .mesh import Mesh
233 from .util import Progress
235 progress = Progress()
236 progress.set_task("Preparing", 0.0, 0.0)
241 bmesh = o.to_mesh(context.scene, True, "PREVIEW")
242 bmeshes.append(bmesh)
246 mesh.splice(Mesh(bmesh))
248 progress.set_task("Smoothing", 0.05, 0.35)
249 if self.smoothing=="NONE":
251 mesh.split_smooth(progress)
253 if self.smoothing!="BLENDER":
254 mesh.compute_normals()
256 if self.material_tex and mesh.materials:
257 mesh.generate_material_uv()
260 if mesh.uv_layers and self.export_uv!="NONE":
261 # Figure out which UV layers to export
262 if self.export_uv=="UNIT0":
263 if mesh.uv_layers[0].unit==0:
266 texunits = range(len(mesh.uv_layers))
267 texunits = [(i, mesh.uv_layers[i]) for i in texunits]
268 texunits = [u for u in texunits if not u[1].hidden]
271 # TBN coordinates must be generated before vertices are split by any other layer
272 uv_names = [u.name for i, u in texunits]
273 if self.tbn_uvtex in uv_names:
274 tbn_index = uv_names.index(self.tbn_uvtex)
275 unit = texunits[tbn_index]
276 del texunits[tbn_index]
277 texunits.insert(0, unit)
279 for i, u in texunits:
280 progress.set_task("Splitting UVs", 0.35+0.3*i/len(texunits), 0.35+0.3*(i+1)/len(texunits))
281 mesh.split_uv(i, progress)
282 if self.tbn_vecs and u.name==self.tbn_uvtex:
291 progress.set_task("Creating strips", 0.65, 0.95)
292 strips, loose = self.stripify(mesh, progress)
294 progress.set_task("Writing file", 0.95, 1.0)
296 out_file = OutFile(fn)
298 out_file.begin("mesh")
302 for i, u in texunits:
306 fmt += "_TEXCOORD2%d"%u.unit
308 fmt += "_ATTRIB33_ATTRIB34"
310 out_file.begin("vertices", fmt)
312 uvs = [None]*len(texunits)
315 for v in mesh.vertices:
317 out_file.write("normal3", *v.normal)
319 for i, u in texunits:
322 out_file.write("texcoord2", *v.uvs[i])
324 out_file.write("multitexcoord2", u.unit, *v.uvs[i])
328 out_file.write("attrib3", 3, *v.tan)
331 out_file.write("attrib3", 4, *v.bino)
333 out_file.write("vertex3", *v.co)
336 out_file.begin("batch", "TRIANGLE_STRIP")
340 indices.append(v.index)
342 out_file.write("indices", *indices)
345 out_file.write("indices", *indices)
349 out_file.begin("batch", "TRIANGLES")
351 for i in range(2, len(f.vertices)):
352 out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
355 if self.export_lines and mesh.lines:
356 out_file.write("batch", "LINES")
358 out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
363 out_file.begin("technique")
364 out_file.begin("pass", '""')
366 if self.material_tex:
367 out_file.begin("material")
368 out_file.write("diffuse", 1.0, 1.0, 1.0, 1.0)
371 for u in mesh.uv_layers:
372 if u.name=="material_tex":
374 out_file.begin("texunit", index)
375 out_file.begin("texture2d")
376 out_file.write("min_filter", "NEAREST")
377 out_file.write("mag_filter", "NEAREST")
378 out_file.write("storage", "RGB", len(mesh.materials), 1)
380 for m in mesh.materials:
381 color = [int(c*255) for c in m.diffuse_color]
382 texdata += "\\x%02X\\x%02X\\x%02X"%tuple(color)
384 out_file.write("raw_data", texdata)
388 mat = mesh.materials[0]
389 out_file.begin("material")
390 diff = mat.diffuse_color
391 out_file.write("diffuse", diff.r, diff.g, diff.b, 1.0)
392 amb = diff*mat.ambient
393 out_file.write("ambient", amb.r, amb.g, amb.b, 1.0)
394 spec = mat.specular_color*mat.specular_intensity
395 out_file.write("specular", spec.r, spec.g, spec.b, 1.0)
396 out_file.write("shininess", mat.specular_hardness);
399 if self.textures!="NONE":
400 for slot in mesh.materials[0].texture_slots:
405 if tex.type!="IMAGE":
409 for u in mesh.uv_layers:
410 if u.name==slot.uv_layer:
413 index = mesh.uv_layers[0].unit
415 out_file.begin("texunit", index)
416 if self.textures=="INLINE":
417 out_file.begin("texture2d")
418 out_file.write("min_filter", "LINEAR")
419 out_file.write("storage", "RGBA", tex.image.size[0], tex.image.size[1])
421 for p in tex.image.pixels:
422 texdata += "\\x%02X"%int(p*255)
424 out_file.write("raw_data", texdata)
427 out_file.write("texture", '"%s"'%tex.image.name)
433 progress.set_task("Done", 1.0, 1.0)
436 bpy.data.meshes.remove(m)