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():
118 # Unflag the island for the next phase
122 # Find an unused face with as few unused neighbors as possible, but
123 # at least one. This heuristic gives a preference to faces in corners
124 # or along borders of a non-closed island.
131 score = sum(not n.flag for n in f.get_neighbors())
132 if score>0 and score<best:
137 # Create a strip starting from the face. This will flag the faces.
138 strip = mesh.create_strip(face, self.max_strip_len)
140 island_strips.append(strip)
144 # Couldn't find a candidate face for starting a strip, so we're
145 # done with this island
149 # Find the strip that benefits the most from the current
150 # contents of the vertex cache
152 for i in range(len(island_strips)):
153 hits = cache.test_strip(island_strips[i])
158 strip = island_strips.pop(best)
162 cache.fetch_strip(strip)
164 faces_done += len(island)
166 progress.set_progress(float(faces_done)/len(mesh.faces))
168 # Collect any faces that weren't used in strips
169 loose += [f for f in island if not f.flag]
177 cache = VertexCache(self.cache_size)
180 if self.use_degen_tris and strips:
185 # Generate glue elements, ensuring that the next strip begins at
187 glue = [big_strip[-1], s[0]]
193 total_hits += cache.fetch_strip(glue)
197 total_hits += cache.fetch_strip(s)
200 # Add loose faces to the end. This wastes space, using five
201 # elements per triangle and six elements per quad.
203 order = (-1, -2, 0, 1)
205 order = (0, 1, -1, -2)
206 vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
209 glue = [big_strip[-1], vertices[0]]
212 total_hits += cache.fetch_strip(glue)
214 big_strip += vertices
216 total_hits += cache.fetch_strip(vertices)
223 def export(self, context, fn):
225 objs = context.selected_objects
227 objs = [context.active_object]
230 raise Exception("Nothing to export")
233 raise Exception("Can only export Mesh data")
235 from .mesh import Mesh
236 from .util import Progress
238 progress = Progress()
239 progress.set_task("Preparing", 0.0, 0.0)
244 bmesh = o.to_mesh(context.scene, True, "PREVIEW")
245 bmeshes.append(bmesh)
249 mesh.splice(Mesh(bmesh))
251 progress.set_task("Smoothing", 0.05, 0.35)
252 if self.smoothing=="NONE":
254 mesh.split_smooth(progress)
256 if self.smoothing!="BLENDER":
257 mesh.compute_normals()
259 if self.material_tex and mesh.materials:
260 mesh.generate_material_uv()
263 if mesh.uv_layers and self.export_uv!="NONE":
264 # Figure out which UV layers to export
265 if self.export_uv=="UNIT0":
266 if mesh.uv_layers[0].unit==0:
269 texunits = range(len(mesh.uv_layers))
270 texunits = [(i, mesh.uv_layers[i]) for i in texunits]
271 texunits = [u for u in texunits if not u[1].hidden]
274 # TBN coordinates must be generated before vertices are split by any other layer
275 uv_names = [u.name for i, u in texunits]
276 if self.tbn_uvtex in uv_names:
277 tbn_index = uv_names.index(self.tbn_uvtex)
278 unit = texunits[tbn_index]
279 del texunits[tbn_index]
280 texunits.insert(0, unit)
282 for i, u in texunits:
283 progress.set_task("Splitting UVs", 0.35+0.3*i/len(texunits), 0.35+0.3*(i+1)/len(texunits))
284 mesh.split_uv(i, progress)
285 if self.tbn_vecs and u.name==self.tbn_uvtex:
294 progress.set_task("Creating strips", 0.65, 0.95)
295 strips, loose = self.stripify(mesh, progress)
297 progress.set_task("Writing file", 0.95, 1.0)
299 out_file = OutFile(fn)
301 out_file.begin("mesh")
305 for i, u in texunits:
309 fmt += "_TEXCOORD2%d"%u.unit
311 fmt += "_ATTRIB33_ATTRIB34"
313 out_file.begin("vertices", fmt)
315 uvs = [None]*len(texunits)
318 for v in mesh.vertices:
320 out_file.write("normal3", *v.normal)
322 for i, u in texunits:
325 out_file.write("texcoord2", *v.uvs[i])
327 out_file.write("multitexcoord2", u.unit, *v.uvs[i])
331 out_file.write("attrib3", 3, *v.tan)
334 out_file.write("attrib3", 4, *v.bino)
336 out_file.write("vertex3", *v.co)
339 out_file.begin("batch", "TRIANGLE_STRIP")
343 indices.append(v.index)
345 out_file.write("indices", *indices)
348 out_file.write("indices", *indices)
352 out_file.begin("batch", "TRIANGLES")
354 for i in range(2, len(f.vertices)):
355 out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
358 if self.export_lines and mesh.lines:
359 out_file.write("batch", "LINES")
361 out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
366 out_file.begin("technique")
367 out_file.begin("pass", '""')
369 if self.material_tex:
370 out_file.begin("material")
371 out_file.write("diffuse", 1.0, 1.0, 1.0, 1.0)
374 for u in mesh.uv_layers:
375 if u.name=="material_tex":
377 out_file.begin("texunit", index)
378 out_file.begin("texture2d")
379 out_file.write("min_filter", "NEAREST")
380 out_file.write("mag_filter", "NEAREST")
381 out_file.write("storage", "RGB", len(mesh.materials), 1)
383 for m in mesh.materials:
384 color = [int(c*255) for c in m.diffuse_color]
385 texdata += "\\x%02X\\x%02X\\x%02X"%tuple(color)
387 out_file.write("raw_data", texdata)
391 mat = mesh.materials[0]
392 out_file.begin("material")
393 diff = mat.diffuse_color
394 out_file.write("diffuse", diff.r, diff.g, diff.b, 1.0)
395 amb = diff*mat.ambient
396 out_file.write("ambient", amb.r, amb.g, amb.b, 1.0)
397 spec = mat.specular_color*mat.specular_intensity
398 out_file.write("specular", spec.r, spec.g, spec.b, 1.0)
399 out_file.write("shininess", mat.specular_hardness);
402 if self.textures!="NONE":
403 for slot in mesh.materials[0].texture_slots:
408 if tex.type!="IMAGE":
412 for u in mesh.uv_layers:
413 if u.name==slot.uv_layer:
416 index = mesh.uv_layers[0].unit
418 out_file.begin("texunit", index)
419 if self.textures=="INLINE":
420 out_file.begin("texture2d")
421 out_file.write("min_filter", "LINEAR")
422 out_file.write("storage", "RGBA", tex.image.size[0], tex.image.size[1])
424 for p in tex.image.pixels:
425 texdata += "\\x%02X"%int(p*255)
427 out_file.write("raw_data", texdata)
430 out_file.write("texture", '"%s"'%tex.image.name)
436 progress.set_task("Done", 1.0, 1.0)
439 bpy.data.meshes.remove(m)