From ea3e95735fcd9d6a80d23dbd90667eb2f1c95ef4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 16 May 2019 18:58:55 +0300 Subject: [PATCH] Move material and texture export to their own classes Also move technique properties from Object to Material. --- blender/io_mspgl/__init__.py | 2 +- blender/io_mspgl/datafile.py | 5 + blender/io_mspgl/export_material.py | 106 +++++++++++++++++++ blender/io_mspgl/export_object.py | 152 ++++++---------------------- blender/io_mspgl/export_texture.py | 13 +++ blender/io_mspgl/properties.py | 14 +-- 6 files changed, 162 insertions(+), 130 deletions(-) create mode 100644 blender/io_mspgl/export_material.py create mode 100644 blender/io_mspgl/export_texture.py diff --git a/blender/io_mspgl/__init__.py b/blender/io_mspgl/__init__.py index 30dc6406..b24f28d9 100644 --- a/blender/io_mspgl/__init__.py +++ b/blender/io_mspgl/__init__.py @@ -7,7 +7,7 @@ bl_info = { if "bpy" in locals(): import imp - for sub in "armature", "datafile", "export_armature", "export_mesh", "export_object", "export_scene", "mesh", "properties", "util": + for sub in "armature", "datafile", "export_armature", "export_material", "export_mesh", "export_object", "export_scene", "export_texture", "mesh", "properties", "util": if sub in locals(): imp.reload(locals()[sub]) diff --git a/blender/io_mspgl/datafile.py b/blender/io_mspgl/datafile.py index 42ff454b..18e57c4e 100644 --- a/blender/io_mspgl/datafile.py +++ b/blender/io_mspgl/datafile.py @@ -12,6 +12,11 @@ class Statement: for a in self.args: if type(a)==float: s += " {:#.6g}".format(a) + elif type(a)==bool: + if a: + s += " true" + else: + s += " false" elif type(a)==str: s += ' "{}"'.format(a) elif type(a)==Resource: diff --git a/blender/io_mspgl/export_material.py b/blender/io_mspgl/export_material.py new file mode 100644 index 00000000..3e5210c1 --- /dev/null +++ b/blender/io_mspgl/export_material.py @@ -0,0 +1,106 @@ +import os + +def linear_to_srgb(l): + if l<0.0031308: + return 12.92*l + else: + return 1.055*(l**(1/2.4))-0.055 + +def get_colormap(srgb): + if srgb: + return linear_to_srgb + else: + return lambda x: x + +def image_name(i): + fp = i.filepath + if fp: + return os.path.split(fp)[1] + else: + return i.name + + +class MaterialExporter: + def __init__(self): + self.textures = 'REF' + + def export_technique_resources(self, material, resources): + from .export_texture import TextureExporter + texture_export = TextureExporter() + + mat_name = material.name+".mat" + if mat_name not in resources: + resources[mat_name] = self.export_material(material) + + if self.textures=='INLINE': + for s in material.texture_slots: + if s and s.texture.type=='IMAGE': + tex_name = s.texture.name+".tex2d" + if tex_name not in resources: + resources[tex_name] = texture_export.export_texture(s.texture) + + def export_technique(self, material, *, resources): + from .datafile import Resource, Statement + tech_res = Resource(material.name+".tech") + + mat_res = resources[material.name+".mat"] + image_texture_slots = [s for s in material.texture_slots if s and s.texture.type=='IMAGE'] + + if material.technique: + if not obj.inherit_tech: + return [] + + st = Statement("inherit", material.technique) + for slot in image_texture_slots: + name = image_name(slot.texture.image) + if slot.use_map_color_diffuse: + st.sub.append(Statement("texture", "diffuse_map", name)) + elif slot.use_map_normal: + st.sub.append(Statement("texture", "normal_map", name)) + if material.override_material: + st.sub.append(tech_res.create_reference_statement("material", "surface", mat_res)) + tech_res.statements.append(st) + else: + st = Statement("pass", "") + st.sub.append(tech_res.create_embed_statement("material", mat_res)) + + if self.textures!='NONE': + diffuse_tex = None + for slot in image_texture_slots: + if slot.use_map_color_diffuse: + diffuse_tex = slot.texture + break + + if diffuse_tex: + ss = Statement("texunit", 0) + if self.textures=='INLINE': + tex_res = resources[slot.texture.name+".tex2d"] + ss.sub.append(tech_res.create_embed_statement("texture2d", tex_res)) + elif tex.image: + ss.sub.append(Statement("texture", image_name(tex.image))) + st.sub.append(ss) + + tech_res.statements.append(st) + + return tech_res + + def export_material(self, material): + from .datafile import Resource, Statement + mat_res = Resource(material.name+".mat") + statements = mat_res.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 = 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 mat_res diff --git a/blender/io_mspgl/export_object.py b/blender/io_mspgl/export_object.py index 34724221..bcd2c6ec 100644 --- a/blender/io_mspgl/export_object.py +++ b/blender/io_mspgl/export_object.py @@ -1,26 +1,6 @@ import os import mathutils -def linear_to_srgb(l): - if l<0.0031308: - return 12.92*l - else: - return 1.055*(l**(1/2.4))-0.055 - -def get_colormap(srgb): - if srgb: - return linear_to_srgb - else: - return lambda x: x - -def image_name(i): - fp = i.filepath - if fp: - return os.path.split(fp)[1] - else: - return i.name - - class ObjectExporter: def __init__(self): self.show_progress = True @@ -62,6 +42,12 @@ class ObjectExporter: mesh_export.use_degen_tris = self.use_degen_tris return mesh_export + def create_material_exporter(self): + from .export_material import MaterialExporter + material_export = MaterialExporter() + material_export.textures = self.textures + return material_export + def export_to_file(self, context, out_fn): obj = context.active_object @@ -101,6 +87,7 @@ class ObjectExporter: from .mesh import create_mesh_from_object mesh_export = self.create_mesh_exporter() + material_export = self.create_material_exporter() for i, l in enumerate(lods): lod_index = l.lod_index if l.lod_for_parent else 0 @@ -112,16 +99,14 @@ class ObjectExporter: mesh_res = mesh_export.export_mesh(context, mesh, progress) resources[mesh_name] = mesh_res - material = None if l.material_slots and l.material_slots[0].material: material = l.material_slots[0].material - mat_name = material.name+".mat" - if mat_name not in resources: - resources[mat_name] = self.export_material(material) - - tech_name = (material.name if material else l.name)+".tech" - if tech_name not in resources: - resources[tech_name] = self.export_object_technique(l, resources=resources) + tech_name = material.name+".tech" + if tech_name not in resources: + material_export.export_technique_resources(material, resources) + resources[tech_name] = material_export.export_technique(material, resources=resources) + elif "stub.tech" not in resources: + resources["stub.tech"] = self.export_stub_technique() progress.pop_task() @@ -140,7 +125,7 @@ class ObjectExporter: statements.append(Statement("bounding_sphere_hint", *center, radius)) prev_mesh = None - prev_tech = (None, None) + prev_tech = None for i, l in enumerate(lods): lod_st = [] @@ -153,24 +138,22 @@ class ObjectExporter: prev_mesh = l.data.name - mat_name = None - if l.material_slots and l.material_slots[0].material: - mat_name = l.material_slots[0].material.name - - tech = (l.technique, mat_name) - if tech!=prev_tech: - tech_res = resources[(mat_name or l.name)+".tech"] - if l.technique: - if l.inherit_tech: - lod_st.append(obj_res.create_embed_statement("technique", tech_res)) - else: - lod_st.append(Statement("technique", l.technique)) + material = None + if l.material_slots: + material = l.material_slots[0].material + if material: + tech_res = resources[material.name+".tech"] + else: + tech_res = resources["stub.tech"] + + if tech_res.name!=prev_tech: + if material and material.technique and not material.inherit_tech: + lod_st.append(Statement("technique", material.technique)) elif self.separate_tech: lod_st.append(obj_res.create_reference_statement("technique", tech_res)) else: lod_st.append(obj_res.create_embed_statement("technique", tech_res)) - - prev_tech = tech + prev_tech = tech_res.name if i>0: st = Statement("level_of_detail", i) @@ -183,83 +166,8 @@ class ObjectExporter: return obj_res - def export_object_technique(self, obj, *, resources): - material = None - if obj.material_slots: - material = obj.material_slots[0].material - - from .datafile import Resource, Statement, Token - tech_res = Resource((material.name if material else obj.name)+".tech") - - mat_res = None - if material: - mat_res = resources[material.name+".mat"] - - if obj.technique: - if not obj.inherit_tech: - return tech_res - - 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: - st.sub.append(Statement("texture", "diffuse_map", name)) - elif slot.use_map_normal: - st.sub.append(Statement("texture", "normal_map", name)) - if obj.override_material: - st.sub.append(tech_res.create_reference_statement("material", "surface", mat_res)) - tech_res.statements.append(st) - - return tech_res - - pass_st = Statement("pass", "") - if material: - pass_st.sub.append(tech_res.create_embed_statement("material", mat_res)) - - if self.textures!="NONE": - diffuse_tex = None - for slot in material.texture_slots: - if slot and slot.texture.type=="IMAGE" and slot.use_map_color_diffuse: - diffuse_tex = slot.texture - break - - if diffuse_tex: - st = Statement("texunit", 0) - if self.textures=="INLINE": - 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) - 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) - tech_res.statements.append(pass_st) - - return tech_res - - def export_material(self, material): + def export_stub_technique(self): from .datafile import Resource, Statement - mat_res = Resource(material.name+".mat") - statements = mat_res.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 = 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 mat_res + tech_res = Resource("stub.tech") + tech_res.statements.append(Statement("pass", "")) + return tech_res diff --git a/blender/io_mspgl/export_texture.py b/blender/io_mspgl/export_texture.py new file mode 100644 index 00000000..bb3eb28d --- /dev/null +++ b/blender/io_mspgl/export_texture.py @@ -0,0 +1,13 @@ +class TextureExporter: + def export_texture(self, texture): + from .datafile import Resource, Statement, Token + tex_res = Resource(texture.name+".tex2d") + + tex_res.statements.append(Statement("min_filter", Token("LINEAR"))) + tex_res.statements.append(Statement("storage", Token("RGBA"), texture.image.size[0], texture.image.size[1])) + texdata = "" + for p in texture.image.pixels: + texdata += "\\x%02X"%int(p*255) + tex_res.statements.append(Statement("raw_data", texdata)) + + return tex_res diff --git a/blender/io_mspgl/properties.py b/blender/io_mspgl/properties.py index bc2fb482..3d16ff36 100644 --- a/blender/io_mspgl/properties.py +++ b/blender/io_mspgl/properties.py @@ -43,10 +43,6 @@ class MspGLObjectProperties(bpy.types.Panel): def draw(self, context): obj = context.active_object - self.layout.prop(obj, "technique") - self.layout.prop(obj, "inherit_tech") - if obj.inherit_tech: - self.layout.prop(obj, "override_material") self.layout.prop(obj, "compound") self.layout.prop(obj, "lod_for_parent") if obj.lod_for_parent: @@ -68,6 +64,10 @@ class MspGLMaterialProperties(bpy.types.Panel): if not mat: return + self.layout.prop(mat, "technique") + self.layout.prop(mat, "inherit_tech") + if mat.inherit_tech: + self.layout.prop(mat, "override_material") self.layout.prop(mat, "srgb_colors") self.layout.prop(mat, "array_atlas") if mat.array_atlas: @@ -89,13 +89,13 @@ def register_properties(): bpy.types.Mesh.tbn_vecs = bpy.props.BoolProperty(name="TBN vectors", description="Compute tangent and binormal vectors for vertices", default=False) bpy.types.Mesh.tbn_uvtex = bpy.props.StringProperty(name="TBN UV layer", description="UV layer to use as basis for TBN vectors", default="") - bpy.types.Object.technique = bpy.props.StringProperty(name="Technique", description="Name of the technique to use for rendering") - bpy.types.Object.inherit_tech = bpy.props.BoolProperty(name="Inherit technique", description="Inherit from the technique to customize textures") - bpy.types.Object.override_material = bpy.props.BoolProperty(name="Override material", description="Override material in the inherited technique as well", default=True) bpy.types.Object.compound = bpy.props.BoolProperty(name="Compound with parent", description="Join this object to its parent when exporting") bpy.types.Object.lod_for_parent = bpy.props.BoolProperty(name="LoD for parent", description="This object is a level of detail for its parent") bpy.types.Object.lod_index = bpy.props.IntProperty(name="LoD index", description="Index of the level of detail", min=1, max=16, default=1) + bpy.types.Material.technique = bpy.props.StringProperty(name="Technique", description="Name of an external technique to use for rendering") + bpy.types.Material.inherit_tech = bpy.props.BoolProperty(name="Inherit technique", description="Inherit from the technique to customize textures") + bpy.types.Material.override_material = bpy.props.BoolProperty(name="Override material", description="Override material in the inherited technique as well", default=True) bpy.types.Material.srgb_colors = bpy.props.BoolProperty(name="sRGB colors", description="Export material colors as sRGB instead of linear", default=True) bpy.types.Material.array_atlas = bpy.props.BoolProperty(name="Texture array atlas", description="The material is stored in a texture array") bpy.types.Material.array_layer = bpy.props.IntProperty("Texture array layer", description="Layer of the texture array atlas to use") -- 2.45.2