]> git.tdb.fi Git - libs/gl.git/blobdiff - blender/io_mspgl/mesh.py
Support exporting meshes from Blender using patch primitives
[libs/gl.git] / blender / io_mspgl / mesh.py
index fadbcee9a18e7ac1e397559c63eddb68504a2218..3a24db96a07f29a8cd9aacff8e6ede446f7cc81a 100644 (file)
@@ -75,6 +75,13 @@ class VertexGroup:
                        self.weight = 0.0
 
 
+class Batch:
+       def __init__(self, pt):
+               self.primitive_type = pt
+               self.patch_size = 0
+               self.vertices = []
+
+
 class Face:
        def __init__(self, face):
                self.index = face.index
@@ -154,11 +161,12 @@ class Mesh:
        def __init__(self, mesh):
                self.name = mesh.name
 
-               self.winding_test = mesh.winding_test
                self.smoothing = mesh.smoothing
                self.use_uv = mesh.use_uv
                self.tangent_uvtex = mesh.tangent_uvtex
                self.use_strips = mesh.use_strips
+               self.use_patches = mesh.use_patches
+               self.use_lines = mesh.use_lines
                self.vertex_groups = mesh.vertex_groups
 
                # Clone basic data
@@ -205,7 +213,7 @@ class Mesh:
                # where they don't exist
                edge_map = {e.key: e for e in self.edges}
                for f in self.faces:
-                       if len(f.vertices)>4:
+                       if len(f.vertices)>4 and not mesh.use.patches:
                                raise ValueError("Unsupported face on mesh {}: N-gon".format(self.name))
 
                        f.vertices = [self.vertices[i] for i in f.vertices]
@@ -223,7 +231,7 @@ class Mesh:
                                v.edges.append(e)
 
                # Store loose edges as lines
-               if mesh.use_lines:
+               if mesh.use_lines and not mesh.use_patches:
                        self.lines = [Line(e) for e in self.edges if not e.faces]
                else:
                        self.lines = []
@@ -243,7 +251,7 @@ class Mesh:
                                        if normal_prop and normal_prop.texture:
                                                self.tangent_vecs = True
 
-               self.vertex_sequence = []
+               self.batches = []
 
        def transform(self, matrix):
                for v in self.vertices:
@@ -258,12 +266,12 @@ class Mesh:
 
                # Merge materials and form a lookup from source material indices to the
                # merged material list
-               material_atlas = []
+               material_lookup = []
                for m in other.materials:
                        if m in self.materials:
-                               material_atlas.append(self.materials.index(m))
+                               material_lookup.append(self.materials.index(m))
                        else:
-                               material_atlas.append(len(self.materials))
+                               material_lookup.append(len(self.materials))
                                self.materials.append(m)
 
                # Append data and adjust indices where necessary.  Since the data is
@@ -294,7 +302,7 @@ class Mesh:
                        f.index += offset
                        f.loop_indices = range(f.loop_indices.start+offset, f.loop_indices.stop+offset)
                        if other.materials:
-                               f.material_index = material_atlas[f.material_index]
+                               f.material_index = material_lookup[f.material_index]
 
                offset = len(self.edges)
                self.edges += other.edges
@@ -305,6 +313,9 @@ class Mesh:
                self.lines += other.lines
 
        def prepare_triangles(self, task):
+               if self.use_patches:
+                       return
+
                face_count = len(self.faces)
                for i in range(face_count):
                        f = self.faces[i]
@@ -412,30 +423,6 @@ class Mesh:
                                for g in v.groups:
                                        g.group = group_index_map[g.group]
 
-       def apply_material_atlas(self, material_atlas):
-               for m in self.materials:
-                       if m.name not in material_atlas.material_names:
-                               raise Exception("Material atlas {} is not compatible with Mesh {}".format(material_atlas.name, self.name))
-
-               if self.use_uv=='NONE':
-                       return
-
-               layer = UvLayer("material_atlas")
-               if self.use_uv=='UNIT0':
-                       self.uv_layers = [layer]
-                       layer.unit = 0
-               else:
-                       self.uv_layers.append(layer)
-                       used_units = [u.unit for u in self.uv_layers]
-                       layer.unit = next(i for i in itertools.count() if i not in used_units)
-                       self.uv_layers.sort(key=lambda u: u.unit)
-
-               layer.uvs = [(0.0, 0.0)]*len(self.loops)
-               for f in self.faces:
-                       uv = material_atlas.get_material_uv(self.materials[f.material_index])
-                       for i in f.loop_indices:
-                               layer.uvs[i] = uv
-
        def prepare_uv(self, task):
                # Form a list of UV layers referenced by materials with the array atlas
                # property set
@@ -655,10 +642,28 @@ class Mesh:
                        task.set_progress(i/len(self.vertices))
 
        def prepare_sequence(self, task):
-               subtask = task.task("Reordering faces", 0.5)
-               self.reorder_faces(subtask)
+               if self.use_patches:
+                       subtask = task.task("Reordering patches", 0.5)
+                       self.reorder_patches(subtask)
 
-               subtask = task.task("Building sequence", 1.0)
+                       subtask = task.task("Building sequence", 1.0)
+                       self.build_patch_sequence(subtask)
+               else:
+                       subtask = task.task("Reordering faces", 0.5)
+                       self.reorder_faces(subtask)
+
+                       subtask = task.task("Building sequence", 1.0)
+                       if self.use_strips:
+                               self.build_tristrip_sequence(subtask)
+                       else:
+                               self.build_triangle_sequence(subtask)
+
+                       if self.use_lines:
+                               self.build_line_sequence()
+
+               self.reorder_vertices()
+
+       def build_tristrip_sequence(self, task):
                sequence = None
                for i, f in enumerate(self.faces):
                        if sequence:
@@ -682,12 +687,35 @@ class Mesh:
                                        sequence += to_add
 
                        if not sequence:
-                               sequence = f.vertices[:]
-                               self.vertex_sequence.append(sequence)
+                               self.batches.append(Batch("TRIANGLE_STRIP"))
+                               sequence = self.batches[-1].vertices
+                               sequence += f.vertices
 
-                       subtask.set_progress(i/len(self.faces))
+                       task.set_progress(i/len(self.faces))
 
-               self.reorder_vertices()
+       def build_triangle_sequence(self, task):
+               batch = Batch("TRIANGLES")
+               for f in self.faces:
+                       batch.vertices += f.vertices
+               self.batches.append(batch)
+
+       def build_line_sequence(self):
+               batch = Batch("LINES")
+               for l in self.lines:
+                       batch.vertices += l.vertices
+               self.batches.append(batch)
+
+       def build_patch_sequence(self, task):
+               current_size = 0
+               sequence = None
+               for f in self.faces:
+                       if len(f.vertices)!=current_size:
+                               current_size = len(f.vertices)
+                               self.batches.append(Batch("PATCHES"))
+                               self.batches[-1].patch_size = current_size
+                               sequence = self.batches[-1].vertices
+
+                       sequence += f.vertices
 
        def reorder_faces(self, task):
                # Tom Forsyth's vertex cache optimization algorithm
@@ -772,13 +800,41 @@ class Mesh:
                for i, f in enumerate(self.faces):
                        f.index = i
 
+       def reorder_patches(self, task):
+               for f in self.faces:
+                       f.flag = False
+
+               reordered_faces = []
+               n_processed = 0
+
+               while 1:
+                       current_size = 0
+
+                       for f in self.faces:
+                               if f.flag:
+                                       continue
+
+                               if not current_size:
+                                       current_size = len(f.vertices)
+                               elif len(f.vertices)!=current_size:
+                                       continue
+
+                               reordered_faces.append(f)
+                               f.flag = True
+
+                               n_processed += 1
+                               task.set_progress(n_processed/len(self.faces))
+
+                       if not current_size:
+                               break
+
        def reorder_vertices(self):
                for v in self.vertices:
                        v.index = -1
 
                reordered_vertices = []
-               for s in self.vertex_sequence:
-                       for v in s:
+               for b in self.batches:
+                       for v in b.vertices:
                                if v.index<0:
                                        v.index = len(reordered_vertices)
                                        reordered_vertices.append(v)
@@ -794,7 +850,7 @@ class Mesh:
                        e.key = make_edge_key(e.vertices[0].index, e.vertices[1].index)
 
 
-def create_mesh_from_object(ctx, obj, material_atlas):
+def create_mesh_from_object(ctx, obj):
        if obj.type!="MESH":
                raise Exception("Object {} is not a mesh".format(obj.name))
 
@@ -817,7 +873,6 @@ def create_mesh_from_object(ctx, obj, material_atlas):
                bmesh = eval_obj.to_mesh()
 
                # Object.to_mesh does not copy custom properties
-               bmesh.winding_test = o.data.winding_test
                bmesh.smoothing = o.data.smoothing
                bmesh.use_lines = o.data.use_lines
                bmesh.vertex_groups = o.data.vertex_groups
@@ -840,9 +895,6 @@ def create_mesh_from_object(ctx, obj, material_atlas):
 
        mesh.name = obj.data.name
 
-       if material_atlas:
-               mesh.apply_material_atlas(material_atlas)
-
        task = ctx.task("Triangulating", 0.3)
        mesh.prepare_triangles(task)
        task = ctx.task("Smoothing", 0.5)