import bpy
import mathutils
-class VertexCache:
- def __init__(self, size):
- self.size = size
- self.slots = [-1]*self.size
-
- def fetch(self, v):
- hit = v.index in self.slots
- if hit:
- self.slots.remove(v.index)
- self.slots.append(v.index)
- if not hit:
- del self.slots[0]
- return hit
-
- def fetch_strip(self, strip):
- hits = 0
- for v in strip:
- if self.fetch(v):
- hits += 1
- return hits
-
- def test_strip(self, strip):
- hits = 0
- for i in range(len(strip)):
- if i>=self.size:
- break
- if strip[i].index in self.slots[i:]:
- hits += 1
- return hits
-
-
class MeshExporter:
def __init__(self):
self.show_progress = True
self.use_strips = True
self.use_degen_tris = False
- self.max_strip_len = 1024
- self.optimize_cache = True
- self.cache_size = 64
self.material_tex = False
- def stripify(self, mesh, progress=None):
- for f in mesh.faces:
- f.flag = False
-
- faces_done = 0
- strips = []
- loose = []
-
- cache = None
- if self.optimize_cache:
- cache = VertexCache(self.cache_size)
-
- island = []
- face_neighbors = []
- island_strips = []
- while 1:
- if not island:
- # No current island; find any unused face to start from
- queue = []
- for f in mesh.faces:
- if not f.flag:
- f.flag = True
- queue.append(f)
- break
-
- if not queue:
- break
-
- # Find all faces connected to the first one
- while queue:
- face = queue.pop(0)
- island.append(face)
-
- for n in face.get_neighbors():
- if not n.flag:
- n.flag = True
- queue.append(n)
-
- face_neighbors = [f.get_neighbors() for f in island]
-
- # Unflag the island for the next phase
- for f in island:
- f.flag = False
-
- # Find an unused face with as few unused neighbors as possible, but
- # at least one. This heuristic gives a preference to faces in corners
- # or along borders of a non-closed island.
- best = 5
- face = None
- for i, f in enumerate(island):
- if f.flag:
- continue
-
- score = sum(not n.flag for n in face_neighbors[i])
- if score>0 and score<best:
- face = f
- best = score
-
- if face:
- # Create a strip starting from the face. This will flag the faces.
- strip = mesh.create_strip(face, self.max_strip_len)
- if strip:
- island_strips.append(strip)
- else:
- face.flag = True
- else:
- # Couldn't find a candidate face for starting a strip, so we're
- # done with this island
- while island_strips:
- best = 0
- if cache:
- # Find the strip that benefits the most from the current
- # contents of the vertex cache
- best_hits = 0
- for i in range(len(island_strips)):
- hits = cache.test_strip(island_strips[i])
- if hits>best_hits:
- best = i
- best_hits = hits
-
- strip = island_strips.pop(best)
- strips.append(strip)
-
- if cache:
- cache.fetch_strip(strip)
-
- faces_done += len(island)
- progress.set_progress(faces_done/len(mesh.faces))
-
- # Collect any faces that weren't used in strips
- loose += [f for f in island if not f.flag]
- for f in island:
- f.flag = True
-
- island = []
- island_strips = []
-
- if cache:
- cache = VertexCache(self.cache_size)
- total_hits = 0
-
- if self.use_degen_tris and strips:
- big_strip = []
-
- for s in strips:
- if big_strip:
- # Generate glue elements, ensuring that the next strip begins at
- # an even position
- glue = [big_strip[-1], s[0]]
- if len(big_strip)%2:
- glue += [s[0]]
+ def join_strips(self, strips):
+ big_strip = []
- big_strip += glue
- if cache:
- total_hits += cache.fetch_strip(glue)
-
- big_strip += s
- if cache:
- total_hits += cache.fetch_strip(s)
-
- for f in loose:
- # Add loose faces to the end. This wastes space, using five
- # elements per triangle and six elements per quad.
+ for s in strips:
+ if big_strip:
+ # Generate glue elements, ensuring that the next strip begins at
+ # an even position
+ glue = [big_strip[-1], s[0]]
if len(big_strip)%2:
- order = (-1, -2, 0, 1)
- else:
- order = (0, 1, -1, -2)
- vertices = [f.vertices[i] for i in order[:len(f.vertices)]]
-
- if big_strip:
- glue = [big_strip[-1], vertices[0]]
- big_strip += glue
- if cache:
- total_hits += cache.fetch_strip(glue)
+ glue += [s[0]]
- big_strip += vertices
- if cache:
- total_hits += cache.fetch_strip(vertices)
+ big_strip += glue
- strips = [big_strip]
- loose = []
+ big_strip += s
- return strips, loose
+ return big_strip
def export(self, context, out_file, obj=None, progress=None):
if obj is None:
if not progress:
progress = Progress(self.show_progress and context)
- progress.push_task("", 0.0, 0.65)
+ progress.push_task("", 0.0, 0.9)
mesh = create_mesh_from_object(context, obj, progress)
strips = []
loose = mesh.faces
if self.use_strips:
- progress.set_task("Creating strips", 0.65, 0.95)
- strips, loose = self.stripify(mesh, progress)
+ strips = mesh.vertex_sequence
+ if self.use_degen_tris:
+ strips = [self.join_strips(strips)]
+ loose = []
- progress.set_task("Writing file", 0.95, 1.0)
+ progress.set_task("Writing file", 0.9, 1.0)
from .outfile import open_output
out_file = open_output(out_file)