]> git.tdb.fi Git - libs/gl.git/commitdiff
Redesign file writing in the Blender exporter
authorMikko Rasa <tdb@tdb.fi>
Wed, 15 May 2019 21:42:03 +0000 (00:42 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 16 May 2019 19:34:54 +0000 (22:34 +0300)
Instead of writing statements directly to the file as string fragments,
construct an in-memory representation of the exported data first.  This
allows it to be manipulated and combined easier.

blender/io_mspgl/__init__.py
blender/io_mspgl/datafile.py [new file with mode: 0644]
blender/io_mspgl/export_armature.py
blender/io_mspgl/export_mesh.py
blender/io_mspgl/export_object.py
blender/io_mspgl/export_scene.py
blender/io_mspgl/outfile.py [deleted file]

index 724d625be566ee853f7a3f44836c32f34a885e10..30dc6406402c328efbba1f02ac70ccea2ec2aaab 100644 (file)
@@ -7,7 +7,7 @@ bl_info = {
 
 if "bpy" in locals():
        import imp
-       for sub in "armature", "export_armature", "export_mesh", "export_object", "export_scene", "mesh", "outfile", "properties", "util":
+       for sub in "armature", "datafile", "export_armature", "export_mesh", "export_object", "export_scene", "mesh", "properties", "util":
                if sub in locals():
                        imp.reload(locals()[sub])
 
@@ -20,7 +20,7 @@ class ExportMspGLBase(ExportHelper):
        def execute(self, context):
                exporter = self.create_exporter()
                self.prepare_exporter(exporter)
-               exporter.export(context, self.filepath)
+               exporter.export_to_file(context, self.filepath)
                return {"FINISHED"}
 
        def create_exporter(self):
diff --git a/blender/io_mspgl/datafile.py b/blender/io_mspgl/datafile.py
new file mode 100644 (file)
index 0000000..09fb86c
--- /dev/null
@@ -0,0 +1,35 @@
+class Statement:
+       def __init__(self, keyword, *args):
+               self.keyword = keyword
+               self.args = list(args)
+               self.sub = []
+
+       def append(self, v):
+               self.args.append(v)
+
+       def write_to_file(self, f, indent=0):
+               s = self.keyword
+               for a in self.args:
+                       if type(a)==float:
+                               s += " {:#.6g}".format(a)
+                       elif type(a)==str:
+                               s += ' "{}"'.format(a)
+                       else:
+                               s += " {}".format(a)
+
+               tabs = '\t'*indent
+               f.write("{}{}".format(tabs, s))
+               if self.sub:
+                       f.write("\n{}{{\n".format(tabs))
+                       for s in self.sub:
+                               s.write_to_file(f, indent+1)
+                       f.write("{}}};\n".format(tabs))
+               else:
+                       f.write(";\n")
+
+class Token:
+       def __init__(self, text):
+               self.text = text
+
+       def __str__(self):
+               return self.text
index f3f18c8adcb1c8f2cf1c2e20bfb93535012c1cd2..c2ec67125f64c93f49322a5bbbb3e71bde68e485 100644 (file)
@@ -1,21 +1,30 @@
 class ArmatureExporter:
-       def export(self, context, out_file):
+       def export_to_file(self, context, out_fn):
                obj = context.active_object
+
+               statements = self.export_armature(context, obj)
+
+               with open(out_fn, "w") as out_file:
+                       for s in statements:
+                               s.write_to_file(out_file)
+
+       def export_armature(self, obj):
                if obj.type!="ARMATURE":
-                       raise Exception("Can only export Armature data")
+                       raise Exception("Object is not an armature")
 
                from .armature import Armature
-
                armature = Armature(obj.data)
                armature.sort_links()
 
-               from .outfile import open_outfile
-               out_file = open_outfile(out_file)
+               from .datafile import Statement
+               statements = []
 
                for l in armature.links:
-                       out_file.begin("link", '"{}"'.format(l.name))
-                       out_file.write("index", l.index)
+                       st = Statement("link", l.name)
+                       st.sub.append(Statement("index", l.index))
                        if l.parent:
-                               out_file.write("parent", '"{}"'.format(l.parent.name))
-                       out_file.write("base", *tuple(l.base))
-                       out_file.end()
+                               st.sub.append(Statement("parent", l.parent.name))
+                       st.sub.append(Statement("base", *tuple(l.base)))
+                       statements.append(st)
+
+               return statements
index 3e146cad24699d956b1a48bd537d8ffc6ef4f5a3..bb116bda9133f3f8192e5ebfa0f42bc10ad046f1 100644 (file)
@@ -25,69 +25,70 @@ class MeshExporter:
 
                return big_strip
 
-       def export(self, context, out_file, obj=None, progress=None):
-               if obj is None:
-                       obj = context.active_object
+       def export_to_file(self, context, out_fn):
+               obj = context.active_object
 
-               from .mesh import create_mesh_from_object
                from .util import Progress
 
-               if not progress:
-                       progress = Progress(self.show_progress and context)
-               progress.push_task("", 0.0, 0.9)
+               progress = Progress(self.show_progress and context)
+               progress.push_task("", 0.0, 0.95)
+               statements = self.export_mesh(context, obj, progress)
 
-               mesh = create_mesh_from_object(context, obj, progress)
+               with open(out_fn, "w") as out_file:
+                       for s in statements:
+                               s.write_to_file(out_file)
 
-               strips = []
-               loose = mesh.faces
-               if self.use_strips:
-                       strips = mesh.vertex_sequence
-                       if self.use_degen_tris:
-                               strips = [self.join_strips(strips)]
-                       loose = []
+       def export_mesh(self, context, mesh_or_obj, progress):
+               from .mesh import Mesh, create_mesh_from_object
 
-               progress.set_task("Writing file", 0.9, 1.0)
+               if type(mesh_or_obj)==Mesh:
+                       mesh = mesh_or_obj
+               else:
+                       progress.push_task("", 0.0, 0.9)
+                       mesh = create_mesh_from_object(context, mesh_or_obj, progress)
+                       progress.pop_task()
 
-               from .outfile import open_output
-               out_file = open_output(out_file)
+               from .datafile import Statement, Token
 
-               fmt = ["NORMAL3"]
+               statements = []
+
+               st = Statement("vertices", Token("NORMAL3"))
                if mesh.uv_layers:
                        for u in mesh.uv_layers:
                                size = str(len(u.uvs[0]))
                                if u.unit==0:
-                                       fmt.append("TEXCOORD"+size)
+                                       st.append(Token("TEXCOORD"+size))
                                else:
-                                       fmt.append("TEXCOORD%s_%d"%(size, u.unit))
+                                       st.append(Token("TEXCOORD{}_{}".format(size, u.unit)))
                        if mesh.tbn_vecs:
-                               fmt += ["TANGENT3", "BINORMAL3"]
+                               st.append(Token("TANGENT3"))
+                               st.append(Token("BINORMAL3"))
                if mesh.vertex_groups:
-                       fmt.append("ATTRIB%d_5"%(mesh.max_groups_per_vertex*2))
-               fmt.append("VERTEX3")
-               out_file.begin("vertices", *fmt)
+                       st.append(Token("ATTRIB{}_5".format(mesh.max_groups_per_vertex*2)))
+               st.append(Token("VERTEX3"))
+
                normal = None
-               uvs = {}
+               uvs = [None]*len(mesh.uv_layers)
                tan = None
                bino = None
                group = None
                for v in mesh.vertices:
                        if v.normal!=normal:
-                               out_file.write("normal3", *v.normal)
+                               st.sub.append(Statement("normal", *v.normal))
                                normal = v.normal
                        for i, u in enumerate(mesh.uv_layers):
-                               if v.uvs[i]!=uvs.get(i):
-                                       size = str(len(v.uvs[i]))
+                               if v.uvs[i]!=uvs[i]:
                                        if u.unit==0:
-                                               out_file.write("texcoord"+size, *v.uvs[i])
+                                               st.sub.append(Statement("texcoord", *v.uvs[i]))
                                        else:
-                                               out_file.write("multitexcoord"+size, u.unit, *v.uvs[i])
+                                               st.sub.append(Statement("multitexcoord", u.unit, *v.uvs[i]))
                                        uvs[i] = v.uvs[i]
                        if mesh.tbn_vecs:
                                if v.tan!=tan:
-                                       out_file.write("tangent3", *v.tan)
+                                       st.sub.append(Statement("tangent", *v.tan))
                                        tan = v.tan
                                if v.bino!=bino:
-                                       out_file.write("binormal3", *v.bino)
+                                       st.sub.append(Statement("binormal", *v.bino))
                                        bino = v.bino
                        if mesh.vertex_groups:
                                group_attr = [(group_index_map[g.group], g.weight*v.group_weight_scale) for g in v.groups[:mesh.max_groups_per_vertex]]
@@ -95,39 +96,37 @@ class MeshExporter:
                                        group_attr.append((0, 0.0))
                                group_attr = list(itertools.chain(*group_attr))
                                if group_attr!=group:
-                                       out_file.write("attrib%d"%len(group_attr), 5, *group_attr)
+                                       st.sub.append(Statement("attrib", 5, *group_attr))
                                        group = group_attr
-                       out_file.write("vertex3", *v.co)
-               out_file.end()
-               for s in strips:
-                       out_file.begin("batch", "TRIANGLE_STRIP")
-                       indices = []
-                       n = 0
-                       for v in s:
-                               indices.append(v.index)
-                               if len(indices)>=32:
-                                       out_file.write("indices", *indices)
-                                       indices = []
-                       if indices:
-                               out_file.write("indices", *indices)
-                       out_file.end()
-
-               if loose:
-                       out_file.begin("batch", "TRIANGLES")
-                       for f in loose:
-                               for i in range(2, len(f.vertices)):
-                                       out_file.write("indices", f.vertices[0].index, f.vertices[i-1].index, f.vertices[i].index)
-                       out_file.end()
+                       st.sub.append(Statement("vertex", *v.co))
+
+               statements.append(st)
+
+               if self.use_strips:
+                       strips = mesh.vertex_sequence
+                       if self.use_degen_tris:
+                               strips = [self.join_strips(strips)]
+
+                       for s in strips:
+                               st = Statement("batch", Token("TRIANGLE_STRIP"))
+                               for i in range(0, len(s), 32):
+                                       st.sub.append(Statement("indices", *(v.index for v in s[i:i+32])))
+                               statements.append(st)
+               else:
+                       st = Statement("batch", "TRIANGLES")
+                       for f in mesh.faces:
+                               st.sub.append(Statement("indices", *(v.index for v in f.vertices)))
+                       statements.append(st)
 
                if mesh.lines:
-                       out_file.begin("batch", "LINES")
+                       st = Statement("batch", "LINES")
                        for l in mesh.lines:
-                               out_file.write("indices", l.vertices[0].index, l.vertices[1].index)
-                       out_file.end()
+                               st.sub.append(Statement("indices", *(v.index for v in l.vertices)))
+                       statements.append(st)
 
                if mesh.winding_test:
-                       out_file.write("winding", "COUNTERCLOCKWISE")
+                       statements.append(Statement("winding", "COUNTERCLOCKWISE"))
 
-               progress.pop_task()
+               progress.set_progress(1.0)
 
-               return mesh
+               return statements
index 5a707bad216e0250360fa34e13589af558997030..4bc6f450b330a3ca17159ddea6fa9a2ba1ab836e 100644 (file)
@@ -20,36 +20,19 @@ def image_name(i):
        else:
                return i.name
 
-def external_name(out_file, ext, index):
-       path, base = os.path.split(out_file.filename)
-       base = os.path.splitext(base)[0]
-       if index>0:
-               base += "_lod{}".format(index)
-       return path, base+ext
-
 
 class ObjectExporter:
        def __init__(self):
+               self.show_progress = True
+               self.use_strips = True
+               self.use_degen_tris = False
                self.textures = "REF"
                self.separate_mesh = False
                self.separate_tech = False
                self.shared_resources = True
                self.export_lods = True
 
-       def export(self, context, out_file, obj=None, progress=None):
-               if obj is None:
-                       obj = context.active_object
-
-               lods = [obj]
-               for c in obj.children:
-                       if c.lod_for_parent:
-                               if c.lod_index>=len(lods):
-                                       lods += [None]*(c.lod_index+1-len(lods))
-                               lods[c.lod_index] = c
-
-               from .outfile import open_output
-               out_file = open_output(out_file)
-
+       def compute_bounding_sphere(self, obj):
                p1 = max(((v.co, v.co.length) for v in obj.data.vertices), key=lambda x:x[1])[0]
                p2 = max(((v.co, (v.co-p1).length) for v in obj.data.vertices), key=lambda x:x[1])[0]
                center = (p1+p2)/2
@@ -60,103 +43,201 @@ class ObjectExporter:
                                center += d*(1-radius/d.length)/2
                                radius = (radius+d.length)/2
 
-               out_file.write("bounding_sphere_hint", center[0], center[1], center[2], radius)
+               return center, radius
+
+       def make_external_name(self, base_name, resource_name, ext, index):
+               if self.shared_resources:
+                       return resource_name+ext
+               elif lod_index>0:
+                       return "{}_lod{}{}".format(base_name, lod_index, ext)
+               else:
+                       return base_name+ext
+
+       def create_mesh_exporter(self):
+               from .export_mesh import MeshExporter
+               mesh_export = MeshExporter()
+               mesh_export.use_strips = self.use_strips
+               mesh_export.use_degen_tris = self.use_degen_tris
+               return mesh_export
+
+       def export_to_file(self, context, out_fn):
+               obj = context.active_object
+
+               from .util import Progress
+               progress = Progress(self.show_progress and context)
+
+               path, base = os.path.split(out_fn)
+               base = os.path.splitext(base)[0]
+
+               meshes = self.export_object_meshes(context, obj, progress, base_name=base)
+               if self.separate_mesh:
+                       for name, st in meshes.items():
+                               with open(os.path.join(path, name), "w") as out_file:
+                                       for s in st:
+                                               s.write_to_file(out_file)
+
+               if self.separate_tech:
+                       lods = [obj]
+                       if self.export_lods:
+                               lods += [c for c in obj.children if c.lod_for_parent]
+
+                       for l in lods:
+                               lod_index = l.lod_index if l.lod_for_parent else 0
+
+                               material = None
+                               if obj.material_slots:
+                                       material = obj.material_slots[0].material
+
+                               if not l.technique:
+                                       tech_name = self.make_external_name(base, material.name, ".tech", lod_index)
+                                       st = self.export_object_technique(l, base_name=base)
+                                       with open(os.path.join(path, tech_name), "w") as out_file:
+                                               for s in st:
+                                                       s.write_to_file(out_file)
+                               elif material and l.override_material:
+                                       mat_name = self.make_external_name(base, material.name, ".mat", lod_index)
+                                       st = self.export_material(material)
+                                       with open(os.path.join(path, mat_name), "w") as out_file:
+                                               for s in st:
+                                                       s.write_to_file(out_file)
+
+               statements = self.export_object(context, obj, progress, meshes=meshes, base_name=base)
+
+               with open(out_fn, "w") as out_file:
+                       for s in statements:
+                               s.write_to_file(out_file)
+
+       def export_object_meshes(self, context, obj, progress, *, base_name=None):
+               if base_name is None:
+                       base_name = obj.name
+
+               lods = [obj]
+               if self.export_lods:
+                       lods += [c for c in obj.children if c.lod_for_parent]
+
+               from .mesh import create_mesh_from_object
+               mesh_export = self.create_mesh_exporter()
+               meshes = {}
+
+               for i, l in enumerate(lods):
+                       lod_index = l.lod_index if l.lod_for_parent else 0
+                       progress.push_task_slice("LOD {}".format(lod_index), i, len(lods))
+
+                       mesh_name = self.make_external_name(base_name, l.data.name, ".mesh", lod_index)
+                       if mesh_name not in meshes:
+                               mesh = create_mesh_from_object(context, l, progress)
+                               meshes[mesh_name] = mesh_export.export_mesh(context, mesh, progress)
+
+                       progress.pop_task()
+
+               return meshes
+
+       def export_object(self, context, obj, progress, *, meshes=None, base_name=None):
+               if base_name is None:
+                       base_name = obj.name
+
+               if meshes is None:
+                       meshes = self.export_object_meshes(context, obj, progress, base_name=base_name)
+
+               lods = [obj]
+               for c in obj.children:
+                       if c.lod_for_parent:
+                               if c.lod_index>=len(lods):
+                                       lods += [None]*(c.lod_index+1-len(lods))
+                               lods[c.lod_index] = c
+
+               from .datafile import Statement
+               statements = []
+
+               center, radius = self.compute_bounding_sphere(obj)
+               statements.append(Statement("bounding_sphere_hint", *center, radius))
 
                prev_mesh = None
                prev_tech = (None, None)
                for i, l in enumerate(lods):
-                       if i>0:
-                               out_file.begin("level_of_detail", i)
+                       lod_st = []
+
+                       if l.data.name!=prev_mesh:
+                               mesh_name = self.make_external_name(base_name, l.data.name, ".mesh", i)
+                               if self.separate_mesh:
+                                       lod_st.append(Statement("mesh", mesh_name))
+                               else:
+                                       st = Statement("mesh")
+                                       st.sub = meshes[mesh_name]
+                                       lod_st.append(st)
 
-                       if i==0 or l.data.name!=prev_mesh:
-                               mesh = self.export_object_mesh(context, out_file, l, progress)
                                prev_mesh = l.data.name
 
-                       same_tech = True
-                       mat = None
+                       mat_name = None
                        if l.material_slots and l.material_slots[0].material:
-                               mat = l.material_slots[0].material.name
-                               if mat!=prev_tech[1]:
-                                       same_tech = False
-                       if l.technique!=prev_tech[0]:
-                               same_tech = False
-                       if i==0 or not same_tech:
-                               self.export_object_technique(l, out_file, i)
-                               prev_tech = (l.technique, mat)
+                               mat_name = l.material_slots[0].material.name
 
-                       if i>0:
-                               out_file.end()
+                       tech = (l.technique, mat_name)
+                       if tech!=prev_tech:
+                               tech_name = self.make_external_name(base_name, mat_name or l.name, ".tech", i)
+                               if l.technique:
+                                       if l.inherit_tech:
+                                               st = Statement("technique")
+                                               st.sub = self.export_object_technique(l, base_name=base_name)
+                                               lod_st.append(st)
+                                       else:
+                                               lod_st.append(Statement("technique", l.technique))
+                               elif self.separate_tech:
+                                       lod_st.append(Statement("technique", tech_name))
+                               else:
+                                       st = Statement("technique")
+                                       st.sub = self.export_object_technique(l, base_name=base_name)
+                                       lod_st.append(st)
 
-       def export_object_mesh(self, context, out_file, obj, progress):
-               from .export_mesh import MeshExporter
-               mesh_export = MeshExporter()
-               for k, v in self.__dict__.items():
-                       setattr(mesh_export, k, v)
+                               prev_tech = tech
 
-               lod_index = 0
-               if obj.lod_for_parent:
-                       lod_index = obj.lod_index
+                       if i>0:
+                               st = Statement("level_of_detail", i)
+                               st.sub = lod_st
+                               statements.append(st)
+                       else:
+                               statements += lod_st
 
-               if self.separate_mesh:
-                       from .outfile import open_output
-                       path, name = external_name(out_file, ".mesh", lod_index)
-                       if self.shared_resources:
-                               name = obj.data.name+".mesh"
-                       mesh_out = open_output(os.path.join(path, name))
-                       mesh = mesh_export.export(context, mesh_out, obj, progress)
-                       out_file.write("mesh", '"{}"'.format(name))
-               else:
-                       out_file.begin("mesh")
-                       mesh = mesh_export.export(context, out_file, obj, progress)
-                       out_file.end()
+               progress.set_progress(1.0)
 
-               return mesh
+               return statements
+
+       def export_object_technique(self, obj, *, base_name=None):
+               if base_name is None:
+                       base_name = obj.name
 
-       def export_object_technique(self, obj, out_file, lod_index):
                material = None
                if obj.material_slots:
                        material = obj.material_slots[0].material
 
-               from .outfile import open_output
-               path, name = external_name(out_file, ".tech", lod_index)
+               from .datafile import Statement, Token
+               statements = []
 
                if obj.technique:
-                       if obj.inherit_tech and material and (obj.override_material or material.texture_slots):
-                               out_file.begin("technique")
-                               out_file.begin("inherit", '"{}"'.format(obj.technique))
+                       if not obj.inherit_tech:
+                               return []
+
+                       st = Statement("inherit", obj.technique)
+                       if material:
                                for slot in material.texture_slots:
                                        if slot and slot.texture.type=="IMAGE":
                                                name = image_name(slot.texture.image)
                                                if slot.use_map_color_diffuse:
-                                                       out_file.write("texture", '"diffuse_map"', '"{}"'.format(name))
+                                                       st.sub.append(Statement("texture", "diffuse_map", name))
                                                elif slot.use_map_normal:
-                                                       out_file.write("texture", '"normal_map"', '"{}"'.format(name))
+                                                       st.sub.append(Statement("texture", "normal_map", name))
                                if obj.override_material:
-                                       mat_name = material.name+".mat"
-                                       mat_out = open_output(os.path.join(path, mat_name))
-                                       self.export_material(material, mat_out)
-                                       out_file.write("material", '"surface"', '"{}"'.format(mat_name))
-                               out_file.end()
-                               out_file.end()
-                       else:
-                               out_file.write("technique", '"{}"'.format(obj.technique))
-               elif self.separate_tech:
-                       if self.shared_resources and material:
-                               name = material.name+".tech"
-                       tech_out = open_output(os.path.join(path, name))
-                       self.export_technique_definition(material, tech_out)
-                       out_file.write("technique", '"{}"'.format(name))
-               else:
-                       out_file.begin("technique")
-                       self.export_technique_definition(material, out_file)
-                       out_file.end()
+                                       mat_name = self.make_external_name(base_name, material.name, ".mat", obj.lod_index)
+                                       st.sub.append(Statement("material", "surface", mat_name))
+                       statements.append(st)
 
-       def export_technique_definition(self, material, out_file):
-               out_file.begin("pass", '""')
+                       return statements
+
+               pass_st = Statement("pass", "")
                if material:
-                       out_file.begin("material")
-                       self.export_material(material, out_file)
-                       out_file.end()
+                       st = Statement("material")
+                       st.sub = self.export_material(material)
+                       pass_st.sub.append(st)
 
                        if self.textures!="NONE":
                                diffuse_tex = None
@@ -166,34 +247,39 @@ class ObjectExporter:
                                                break
 
                                if diffuse_tex:
-                                       out_file.begin("texunit", 0)
+                                       st = Statement("texunit", 0)
                                        if self.textures=="INLINE":
-                                               out_file.begin("texture2d")
-                                               out_file.write("min_filter", "LINEAR")
-                                               out_file.write("storage", "RGBA", diffuse_tex.image.size[0], diffuse_tex.image.size[1])
-                                               texdata = '"'
-                                               for p in diffuse_tex.image.pixels:
+                                               ss = Statement("texture2d")
+                                               ss.sub.append(Statement("min_filter", Token("LINEAR")))
+                                               ss.sub.append(Statement("storage", Token("RGBA"), tex.image.size[0], tex.image.size[1]))
+                                               texdata = ""
+                                               for p in tex.image.pixels:
                                                        texdata += "\\x%02X"%int(p*255)
-                                               texdata += '"'
-                                               out_file.write("raw_data", texdata)
-                                               out_file.end()
-                                       else:
-                                               out_file.write("texture", '"%s"'%image_name(diffuse_tex.image))
-                                       out_file.end()
+                                               ss.sub.append(Statement("raw_data", texdata))
+                                               st.sub.append(ss)
+                                       elif tex.image:
+                                               st.sub.append(Statement("texture", image_name(tex.image)))
+                                       pass_st.sub.append(st)
+               statements.append(pass_st)
 
-               out_file.end()
+               return statements
 
-       def export_material(self, mat, out_file):
-               cm = get_colormap(mat.srgb_colors)
-               if any((s and s.use_map_color_diffuse) for s in mat.texture_slots):
-                       out_file.write("diffuse", 1.0, 1.0, 1.0, 1.0)
-                       amb = cm(mat.ambient)
-                       out_file.write("ambient", amb, amb, amb, 1.0)
+       def export_material(self, material):
+               from .datafile import Statement
+               statements = []
+
+               cm = get_colormap(material.srgb_colors)
+               if any(s.use_map_color_diffuse for s in material.texture_slots if s):
+                       statements.append(Statement("diffuse", 1.0, 1.0, 1.0, 1.0))
+                       amb = cm(material.ambient)
+                       statements.append(Statement("ambient", amb, amb, amb, 1.0))
                else:
-                       diff = mat.diffuse_color*mat.diffuse_intensity
-                       out_file.write("diffuse", cm(diff.r), cm(diff.g), cm(diff.b), 1.0)
-                       amb = diff*mat.ambient
-                       out_file.write("ambient", cm(amb.r), cm(amb.g), cm(amb.b), 1.0)
-               spec = mat.specular_color*mat.specular_intensity
-               out_file.write("specular", spec.r, spec.g, spec.b, 1.0)
-               out_file.write("shininess", mat.specular_hardness)
+                       diff = material.diffuse_color*material.diffuse_intensity
+                       statements.append(Statement("diffuse", cm(diff.r), cm(diff.g), cm(diff.b), 1.0))
+                       amb = diff*material.ambient
+                       statements.append(Statement("ambient", cm(amb.r), cm(amb.g), cm(amb.b), 1.0))
+               spec = material.specular_color*material.specular_intensity
+               statements.append(Statement("specular", cm(spec.r), cm(spec.g), cm(spec.g), 1.0))
+               statements.append(Statement("shininess", material.specular_hardness))
+
+               return statements
index d51fb4718a0fdf1afda48a9587bf670dcbe3732e..f6776107413955964d0e3e757bc5594e3a69d03f 100644 (file)
@@ -6,14 +6,11 @@ class SceneExporter:
                self.resource_collection = True
                self.show_progress = True
 
-       def export(self, context, out_file):
-               objs = context.selected_objects
-               objs = [o for o in objs if o.type=="MESH" and (not o.compound or o.parent not in objs) and not o.lod_for_parent]
+       def export_to_file(self, context, out_fn):
+               objs = [o for o in context.selected_objects if o.type=="MESH" and not o.lod_for_parent]
+               objs = [o for o in objs if (not o.compound or o.parent not in objs)]
 
-               from .outfile import open_output
-               out_file = open_output(out_file)
-
-               path, base = os.path.split(out_file.filename)
+               path, base = os.path.split(out_fn)
                base, ext = os.path.splitext(base)
 
                from .export_object import ObjectExporter
@@ -46,32 +43,44 @@ class SceneExporter:
                from .util import Progress
                progress = Progress(self.show_progress and context)
 
-               if self.resource_collection:
-                       res_out = open_output(os.path.join(path, base+"_resources.mdc"))
+               from .export_object import ObjectExporter
+               object_export = ObjectExporter()
 
-                       # TODO Export techniques as separate items in the collection
-                       for i, o in enumerate(unique_objects):
-                               res_out.begin("object", '"{}.object"'.format(o.name))
-                               progress.push_task_slice(o.name, i, len(objs))
-                               object_export.export(context, res_out, o, progress)
-                               progress.pop_task()
-                               res_out.end()
+               from .datafile import Statement
+               if self.resource_collection:
+                       with open(os.path.join(path, base+"_resources.mdc"), "w") as res_out:
+                               for i, o in enumerate(unique_objects):
+                                       progress.push_task_slice(o.name, i, len(unique_objects))
+                                       st = Statement("object", "{}.object".format(o.name))
+                                       st.sub = object_export.export_object(context, o, progress)
+                                       st.write_to_file(res_out)
+                                       progress.pop_task()
                else:
-                       object_export.separate_mesh = True
-                       object_export.separate_tech = True
                        res_dir = os.path.join(path, base+"_resources")
                        if not os.path.exists(res_dir):
                                os.makedirs(res_dir)
                        for i, o in enumerate(unique_objects):
-                               obj_out = open_output(os.path.join(res_dir, o.name+".object"))
-                               progress.push_task_slice(o.name, i, len(objs))
-                               object_export.export(context, obj_out, o, progress)
+                               progress.push_task_slice(o.name, i, len(unique_objects))
+                               st = object_export.export_object(context, o, progress)
+                               with open(os.path.join(res_dir, o.name+".object"), "w") as obj_out:
+                                       for s in st:
+                                               s.write_to_file(obj_out)
                                progress.pop_task()
 
+               statements = self.export_scene(context, objs, progress, prototypes=object_prototypes)
+
+               with open(out_fn, "w") as out_file:
+                       for s in statements:
+                               s.write_to_file(out_file)
+
+       def export_scene(self, context, objs, progress, *, prototypes=None):
+               from .datafile import Statement
+               statements = []
+
                for o in objs:
-                       out_file.begin("object", '"{}.object"'.format(object_prototypes[o.name].name))
+                       st = Statement("object", "{}.object".format(prototypes[o.name].name))
                        # XXX Parent relationships screw up the location and rotation
-                       out_file.write("position", o.location[0], o.location[1], o.location[2])
+                       st.sub.append(Statement("position", o.location[0], o.location[1], o.location[2]))
                        if o.rotation_mode=="AXIS_ANGLE":
                                angle = o.rotation_axis_angle[0]
                                axis = o.rotation_axis_angle[1:]
@@ -82,6 +91,10 @@ class SceneExporter:
                                        q = o.rotation_euler.to_quaternion()
                                angle = q.angle
                                axis = q.axis
-                       out_file.write("rotation", angle*180/math.pi, axis[0], axis[1], axis[2])
-                       out_file.write("scale", o.scale[0], o.scale[1], o.scale[2])
-                       out_file.end()
+                       st.sub.append(Statement("rotation", angle*180/math.pi, axis[0], axis[1], axis[2]))
+                       st.sub.append(Statement("scale", o.scale[0], o.scale[1], o.scale[2]))
+                       statements.append(st)
+
+               progress.set_progress(1.0)
+
+               return statements
diff --git a/blender/io_mspgl/outfile.py b/blender/io_mspgl/outfile.py
deleted file mode 100644 (file)
index 2c747a8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-import sys
-
-class OutFile:
-       def __init__(self, fn):
-               self.filename = fn
-               if fn==None:
-                       self.file = sys.stdout
-               else:
-                       self.file = open(fn, "w")
-               self.indent = 0
-
-       def make(self, kwd, *params):
-               pstr = ""
-               for p in params:
-                       if type(p)==float:
-                               pstr += " %#.6g"%p
-                       else:
-                               pstr += " %s"%p
-               return "%s%s"%(kwd, pstr)
-
-       def write(self, kwd, *params):
-               self.file.write("%s%s;\n"%('\t'*self.indent, self.make(kwd, *params)))
-
-       def begin(self, kwd, *params):
-               i = '\t'*self.indent
-               self.file.write("%s%s\n%s{\n"%(i, self.make(kwd, *params), i))
-               self.indent += 1
-
-       def end(self):
-               self.indent -= 1
-               self.file.write("%s};\n"%('\t'*self.indent))
-
-
-def open_output(f):
-       if isinstance(f, OutFile):
-               return f
-       return OutFile(f)