2 from .outfile import OutFile
5 def __init__(self, size):
7 self.slots = [-1]*self.size
10 hit = v.index in self.slots
12 self.slots.remove(v.index)
13 self.slots.append(v.index)
18 def fetch_strip(self, strip):
25 def test_strip(self, strip):
27 for i in range(len(strip)):
30 if strip[i].index in self.slots[i:]:
37 self.use_strips = True
38 self.use_degen_tris = True
39 self.max_strip_len = 1024
40 self.optimize_cache = False
42 self.export_lines = True
43 self.export_uv = "UNIT0"
48 self.material_tex = False
50 self.smoothing = "MSPGL"
52 def stripify(self, mesh, progress = None):
61 if self.optimize_cache:
62 cache = VertexCache(self.cache_size)
68 # No current island; find any unused face to start from
79 # Find all faces connected to the first one
84 for n in f.get_neighbors():
89 # Unflag the island for the next phase
93 # Find an unused face with as few unused neighbors as possible, but
94 # at least one. This heuristic gives a preference to faces in corners
95 # or along borders of a non-closed island.
102 score = sum(not n.flag for n in f.get_neighbors())
103 if score>0 and score<best:
108 # Create a strip starting from the face. This will flag the faces.
109 strip = mesh.create_strip(face, self.max_strip_len)
111 island_strips.append(strip)
115 # Couldn't find a candidate face for starting a strip, so we're
116 # done with this island
120 # Find the strip that benefits the most from the current
121 # contents of the vertex cache
123 for i in range(len(island_strips)):
124 hits = cache.test_strip(island_strips[i])
129 strip = island_strips.pop(best)
133 cache.fetch_strip(strip)
135 faces_done += len(island)
137 progress.set_progress(float(faces_done)/len(mesh.faces))
139 # Collect any faces that weren't used in strips
140 loose += [f for f in island if not f.flag]
148 cache = VertexCache(self.cache_size)
151 if self.use_degen_tris and strips:
156 # Generate glue elements, ensuring that the next strip begins at
158 glue = [big_strip[-1], s[0]]
164 total_hits += cache.fetch_strip(glue)
168 total_hits += cache.fetch_strip(s)
171 # Add loose faces to the end. This wastes space, using five
172 # elements per triangle and six elements per quad.
174 order = (-1, -2, 0, 1)
176 order = (0, 1, -1, -2)
177 vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
180 glue = [big_strip[-1], vertices[0]]
183 total_hits += cache.fetch_strip(glue)
185 big_strip += vertices
187 total_hits += cache.fetch_strip(vertices)
194 def export(self, context, fn):
196 objs = context.selected_objects
198 objs = [context.active_object]
201 raise Exception("Nothing to export")
204 raise Exception("Can only export Mesh data")
206 from .mesh import Mesh
207 from .util import Progress
209 progress = Progress()
210 progress.set_task("Preparing", 0.0, 0.0)
215 bmesh = o.to_mesh(context.scene, True, "PREVIEW")
216 bmeshes.append(bmesh)
220 mesh.splice(Mesh(bmesh))
222 progress.set_task("Smoothing", 0.05, 0.35)
223 if self.smoothing=="NONE":
225 mesh.split_smooth(progress)
227 if self.smoothing!="BLENDER":
228 mesh.compute_normals()
230 if self.material_tex and mesh.materials:
231 mesh.generate_material_uv()
234 if mesh.uv_layers and self.export_uv!="NONE":
235 # Figure out which UV layers to export
236 if self.export_uv=="UNIT0":
237 if mesh.uv_layers[0].unit==0:
240 texunits = range(len(mesh.uv_layers))
241 texunits = [(i, mesh.uv_layers[i]) for i in texunits]
242 texunits = [u for u in texunits if not u[1].hidden]
245 # TBN coordinates must be generated before vertices are split by any other layer
246 uv_names = [u.name for i, u in texunits]
247 if self.tbn_uvtex in uv_names:
248 tbn_index = uv_names.index(self.tbn_uvtex)
249 unit = texunits[tbn_index]
250 del texunits[tbn_index]
251 texunits.insert(0, unit)
253 for i, u in texunits:
254 progress.set_task("Splitting UVs", 0.35+0.3*i/len(texunits), 0.35+0.3*(i+1)/len(texunits))
255 mesh.split_uv(i, progress)
256 if self.tbn_vecs and u.name==self.tbn_uvtex:
265 progress.set_task("Creating strips", 0.65, 0.95)
266 strips, loose = self.stripify(mesh, progress)
268 progress.set_task("Writing file", 0.95, 1.0)
270 out_file = OutFile(fn)
272 out_file.begin("mesh")
276 for i, u in texunits:
280 fmt += "_TEXCOORD2%d"%u.unit
282 fmt += "_ATTRIB33_ATTRIB34"
284 out_file.begin("vertices", fmt)
286 uvs = [None]*len(texunits)
289 for v in mesh.vertices:
291 out_file.write("normal3", *v.normal)
293 for i, u in texunits:
296 out_file.write("texcoord2", *v.uvs[i])
298 out_file.write("multitexcoord2", u.unit, *v.uvs[i])
302 out_file.write("attrib3", 3, *v.tan)
305 out_file.write("attrib3", 4, *v.bino)
307 out_file.write("vertex3", *v.co)
310 out_file.begin("batch", "TRIANGLE_STRIP")
314 indices.append(v.index)
316 out_file.write("indices", *indices)
319 out_file.write("indices", *indices)
323 out_file.begin("batch", "TRIANGLES")
325 for i in range(2, len(f.vertices)):
326 out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
329 if self.export_lines and mesh.lines:
330 out_file.write("batch", "LINES")
332 out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
337 out_file.begin("technique")
338 out_file.begin("pass", '""')
340 if self.material_tex:
341 out_file.begin("material")
342 out_file.write("diffuse", 1.0, 1.0, 1.0, 1.0)
345 for u in mesh.uv_layers:
346 if u.name=="material_tex":
348 out_file.begin("texunit", index)
349 out_file.begin("texture2d")
350 out_file.write("min_filter", "NEAREST")
351 out_file.write("mag_filter", "NEAREST")
352 out_file.write("storage", "RGB", len(mesh.materials), 1)
354 for m in mesh.materials:
355 color = [int(c*255) for c in m.diffuse_color]
356 texdata += "\\x%02X\\x%02X\\x%02X"%tuple(color)
358 out_file.write("raw_data", texdata)
362 mat = mesh.materials[0]
363 out_file.begin("material")
364 diff = mat.diffuse_color
365 out_file.write("diffuse", diff.r, diff.g, diff.b, 1.0)
366 amb = diff*mat.ambient
367 out_file.write("ambient", amb.r, amb.g, amb.b, 1.0)
368 spec = mat.specular_color*mat.specular_intensity
369 out_file.write("specular", spec.r, spec.g, spec.b, 1.0)
370 out_file.write("shininess", mat.specular_hardness);
373 if self.textures!="NONE":
374 for slot in mesh.materials[0].texture_slots:
379 if tex.type!="IMAGE":
383 for u in mesh.uv_layers:
384 if u.name==slot.uv_layer:
387 index = mesh.uv_layers[0].unit
389 out_file.begin("texunit", index)
390 if self.textures=="INLINE":
391 out_file.begin("texture2d")
392 out_file.write("min_filter", "LINEAR")
393 out_file.write("storage", "RGBA", tex.image.size[0], tex.image.size[1])
395 for p in tex.image.pixels:
396 texdata += "\\x%02X"%int(p*255)
398 out_file.write("raw_data", texdata)
401 out_file.write("texture", '"%s"'%tex.image.name)
407 progress.set_task("Done", 1.0, 1.0)
410 bpy.data.meshes.remove(m)