6 def __init__(self, size):
8 self.slots = [-1]*self.size
11 hit = v.index in self.slots
13 self.slots.remove(v.index)
14 self.slots.append(v.index)
19 def fetch_strip(self, strip):
26 def test_strip(self, strip):
28 for i in range(len(strip)):
31 if strip[i].index in self.slots[i:]:
38 self.show_progress = True
39 self.use_strips = True
40 self.use_degen_tris = False
41 self.max_strip_len = 1024
42 self.optimize_cache = True
44 self.material_tex = False
46 def stripify(self, mesh, progress=None):
55 if self.optimize_cache:
56 cache = VertexCache(self.cache_size)
63 # No current island; find any unused face to start from
74 # Find all faces connected to the first one
79 for n in face.get_neighbors():
84 face_neighbors = [f.get_neighbors() for f in island]
86 # Unflag the island for the next phase
90 # Find an unused face with as few unused neighbors as possible, but
91 # at least one. This heuristic gives a preference to faces in corners
92 # or along borders of a non-closed island.
95 for i, f in enumerate(island):
99 score = sum(not n.flag for n in face_neighbors[i])
100 if score>0 and score<best:
105 # Create a strip starting from the face. This will flag the faces.
106 strip = mesh.create_strip(face, self.max_strip_len)
108 island_strips.append(strip)
112 # Couldn't find a candidate face for starting a strip, so we're
113 # done with this island
117 # Find the strip that benefits the most from the current
118 # contents of the vertex cache
120 for i in range(len(island_strips)):
121 hits = cache.test_strip(island_strips[i])
126 strip = island_strips.pop(best)
130 cache.fetch_strip(strip)
132 faces_done += len(island)
134 progress.set_progress(float(faces_done)/len(mesh.faces))
136 # Collect any faces that weren't used in strips
137 loose += [f for f in island if not f.flag]
145 cache = VertexCache(self.cache_size)
148 if self.use_degen_tris and strips:
153 # Generate glue elements, ensuring that the next strip begins at
155 glue = [big_strip[-1], s[0]]
161 total_hits += cache.fetch_strip(glue)
165 total_hits += cache.fetch_strip(s)
168 # Add loose faces to the end. This wastes space, using five
169 # elements per triangle and six elements per quad.
171 order = (-1, -2, 0, 1)
173 order = (0, 1, -1, -2)
174 vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
177 glue = [big_strip[-1], vertices[0]]
180 total_hits += cache.fetch_strip(glue)
182 big_strip += vertices
184 total_hits += cache.fetch_strip(vertices)
191 def export(self, context, out_file, obj=None, progress=None):
193 obj = context.active_object
195 from .mesh import create_mesh_from_object
196 from .util import Progress
198 if self.show_progress:
200 progress = Progress(context)
201 progress.set_task("Preparing", 0.0, 0.0)
205 mesh = create_mesh_from_object(context, obj, progress)
211 progress.set_task("Creating strips", 0.65, 0.95)
212 strips, loose = self.stripify(mesh, progress)
215 progress.set_task("Writing file", 0.95, 1.0)
217 from .outfile import open_output
218 out_file = open_output(out_file)
222 for u in mesh.uv_layers:
223 size = str(len(u.uvs[0]))
225 fmt.append("TEXCOORD"+size)
227 fmt.append("TEXCOORD%s_%d"%(size, u.unit))
229 fmt += ["TANGENT3", "BINORMAL3"]
230 if mesh.vertex_groups:
231 fmt.append("ATTRIB%d_5"%(mesh.max_groups_per_vertex*2))
232 fmt.append("VERTEX3")
233 out_file.begin("vertices", *fmt)
239 for v in mesh.vertices:
241 out_file.write("normal3", *v.normal)
243 for i, u in enumerate(mesh.uv_layers):
244 if v.uvs[i]!=uvs.get(i):
245 size = str(len(v.uvs[i]))
247 out_file.write("texcoord"+size, *v.uvs[i])
249 out_file.write("multitexcoord"+size, u.unit, *v.uvs[i])
253 out_file.write("tangent3", *v.tan)
256 out_file.write("binormal3", *v.bino)
258 if mesh.vertex_groups:
259 group_attr = [(group_index_map[g.group], g.weight*v.group_weight_scale) for g in v.groups[:mesh.max_groups_per_vertex]]
260 while len(group_attr)<mesh.max_groups_per_vertex:
261 group_attr.append((0, 0.0))
262 group_attr = list(itertools.chain(*group_attr))
263 if group_attr!=group:
264 out_file.write("attrib%d"%len(group_attr), 5, *group_attr)
266 out_file.write("vertex3", *v.co)
269 out_file.begin("batch", "TRIANGLE_STRIP")
273 indices.append(v.index)
275 out_file.write("indices", *indices)
278 out_file.write("indices", *indices)
282 out_file.begin("batch", "TRIANGLES")
284 for i in range(2, len(f.vertices)):
285 out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
289 out_file.begin("batch", "LINES")
291 out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
294 if mesh.winding_test:
295 out_file.write("winding", "COUNTERCLOCKWISE")
298 progress.set_task("Done", 1.0, 1.0)