OSDN Git Service

add pymeshio.
[meshio/meshio.git] / swig / blender / mqo_export.py
index 09b91b8..33f8d38 100644 (file)
-#!BPY\r
-# coding: utf-8\r
-\r
-"""\r
-Name: 'Metasequoia (.mqo)...'\r
-Blender: 245\r
-Group: 'Export'\r
-Tooltip: 'Save as Metasequoia MQO File'\r
-"""\r
-__author__= 'ousttrue'\r
-__url__ = ["http://gunload.web.fc2.com/blender/"]\r
-__version__= '0.3 2010/06/06'\r
-__bpydoc__ = """\\r
-This script is an exporter to MQO file format.\r
-\r
-Usage:\r
-\r
-Run this script from "File->Export" menu.\r
-\r
-0.1 20080128:\r
-0.2 20100518: refactoring.\r
-0.3 20100606: integrate 2.4 and 2.5.\r
-"""\r
-\r
-\r
-###############################################################################\r
-# import\r
-###############################################################################\r
-import os\r
-import sys\r
-\r
-def isBlender24():\r
-    return sys.version_info[0]<3\r
-\r
-if isBlender24():\r
-    # for 2.4\r
-    import Blender\r
-    from Blender import Mathutils\r
-    import bpy\r
-\r
-    # wrapper\r
-    import bl24 as bl\r
-\r
-else:\r
-    # for 2.5\r
-    import bpy\r
-    from bpy.props import *\r
-\r
-    # wrapper\r
-    import bl25 as bl\r
-\r
-def apply_transform(vec, matrix):\r
-    x, y, z = vec\r
-    xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]\r
-    return    x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\\r
-            x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\\r
-            x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc\r
-\r
-def convert_to_mqo(vec):\r
-    return vec.x, vec.z, -vec.y\r
-\r
-\r
-class OutlineNode(object):\r
-    __slots__=['o', 'children']\r
-    def __init__(self, o):\r
-        self.o=o\r
-        self.children=[]\r
-\r
-    def __str__(self):\r
-        return "<Node %s>" % self.o\r
-\r
-\r
-class ObjectInfo(object):\r
-    __slots__=['object', 'depth', 'material_map']\r
-    def __init__(self, o, depth):\r
-        self.object=o\r
-        self.depth=depth\r
-        self.material_map={}\r
-\r
-    def __str__(self):\r
-        return "<ObjectInfo %d %s>" % (self.depth, self.object)\r
-\r
-\r
-class MqoExporter(object):\r
-    __slots__=["materials", "objects", 'scale',]\r
-    def __init__(self, scale):\r
-        self.objects=[]\r
-        self.materials=[]\r
-        self.scale=scale\r
-        print('scaling', self.scale)\r
-\r
-    def setup(self, scene):\r
-        # 木構造を構築する\r
-        object_node_map={}\r
-        for o in scene.objects:\r
-            object_node_map[o]=OutlineNode(o)\r
-        for node in object_node_map.values():\r
-            if node.o.parent:\r
-                object_node_map[node.o.parent].children.append(node)\r
-\r
-        # ルートを得る\r
-        root=object_node_map[scene.objects.active]\r
-\r
-        # 情報を集める\r
-        if root.o.type.upper()=='EMPTY':\r
-            # depth調整 \r
-            for node in root.children:\r
-                self.__setup(node)\r
-        else:\r
-            self.__setup(root)\r
-\r
-    def __setup(self, node, depth=0):\r
-        info=ObjectInfo(node.o, depth)\r
-        self.objects.append(info)\r
-        if node.o.type.upper()=='MESH':\r
-            # set material index\r
-            for i, m in enumerate(node.o.data.materials):\r
-                info.material_map[i]=self.__getOrAddMaterial(m)\r
-        # recursive\r
-        for child in node.children:\r
-            self.__setup(child, depth+1)\r
-            \r
-    def __getOrAddMaterial(self, material):\r
-        for i, m in enumerate(self.materials):\r
-            if m==material:\r
-                return i\r
-        index=len(self.materials)\r
-        self.materials.append(material)\r
-        return index\r
-\r
-    def write(self, path, scene):\r
-        io=bl.Writer(path, 'cp932')\r
-        self.__write_header(io)\r
-        self.__write_scene(io)\r
-        print("Writing MaterialChunk")\r
-        self.__write_materials(io, os.path.dirname(path))\r
-        print("Writing ObjectChunk")\r
-        for info in self.objects:\r
-            self.__write_object(io, info, scene)\r
-        io.write("Eof\r\n")\r
-        io.flush()\r
-        io.close()\r
-\r
-    def __write_header(self, io):\r
-        io.write("Metasequoia Document\r\n")\r
-        io.write("Format Text Ver 1.0\r\n")\r
-        io.write("\r\n")\r
-\r
-    def __write_scene(self, io):\r
-        print("Writing SceneChunk")\r
-        io.write("Scene {\r\n")\r
-        io.write("}\r\n")\r
-\r
-    def __write_materials(self, io, dirname):\r
-        # each material    \r
-        io.write("Material %d {\r\n" % (len(self.materials)))\r
-        for m in self.materials:\r
-            tex, aplane=bl.getTexture(m, dirname)\r
-            if len(tex):\r
-                # textureがある場合は下地を白に\r
-                io.write("\"%s\" shader(3) col(1 1 1 1)" % m.name)\r
-            else:\r
-                # 無い場合はそのまま\r
-                io.write(bl.materialToMqo(m))\r
-            io.write(tex)\r
-            io.write(aplane)\r
-            io.write("\r\n") \r
-        # end of chunk\r
-        io.write("}\r\n") \r
-\r
-    def __write_object(self, io, info, scene):\r
-        #print(info)\r
-\r
-        obj=info.object\r
-        if obj.type.upper()!='MESH':\r
-            return\r
-\r
-        # duplicate and applyMatrix\r
-        mesh, dumy=bl.objectDuplicate(scene, obj)\r
-\r
-        ############################################################\r
-        # write\r
-        ############################################################\r
-        io.write("Object \""+obj.name+"\" {\r\n")\r
-\r
-        # depth\r
-        io.write("\tdepth %d\r\n" % info.depth)\r
-\r
-        # mirroring                \r
-        isMirrorring=False\r
-        for mod in obj.modifiers:\r
-                if mod.name.upper()=="MIRROR":\r
-                        isMirrorring=True\r
-                        break\r
-        if isMirrorring:\r
-                io.write("\tmirror 1\r\n")\r
-                io.write("\tmirror_axis 1\r\n")\r
-\r
-        # vertices\r
-        io.write("\tvertex %d {\r\n" % len(mesh.verts))\r
-        for vert in mesh.verts:\r
-            x, y, z = convert_to_mqo(vert.co)\r
-            io.write("\t\t%f %f %f\r\n" % \r
-                    (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up\r
-        io.write("\t}\r\n")\r
-\r
-        # faces\r
-        io.write("\tface %d {\r\n" % len(mesh.faces))\r
-        for i, face in enumerate(mesh.faces):\r
-            count=bl.faceVertexCount(face)\r
-            # V\r
-            io.write("\t\t%d V(" % count)\r
-            face_list=[]\r
-            for j in bl.faceVertices(face):\r
-                face_list.insert(0, j)\r
-            # flip face\r
-            for j in face_list:\r
-                io.write("%d " % j)\r
-            io.write(")")\r
-            # mat\r
-            if len(mesh.materials):\r
-                io.write(" M(%d)" % \r
-                        info.material_map[bl.faceMaterialIndex(face)])\r
-            # UV\r
-            if bl.meshHasUV(mesh) and bl.faceHasUV(mesh, i, face):\r
-                io.write(" UV(")\r
-                uv_list=[]\r
-                for uv in bl.faceGetUV(mesh, i, face, count):\r
-                    # reverse vertical value\r
-                    uv_list.insert(0, uv)\r
-                # flip face\r
-                for uv in uv_list:\r
-                    io.write("%f %f " % (uv[0], 1.0-uv[1])) \r
-                io.write(")")\r
-            io.write("\r\n")\r
-        io.write("\t}\r\n") # end of faces\r
-        io.write("}\r\n") # end of object\r
-        ############################################################\r
-\r
-        # 削除する\r
-        scene.objects.unlink(dumy)\r
-\r
-\r
-def __execute(filename, scene, scale=10):\r
-    exporter=MqoExporter(scale)\r
-    exporter.setup(scene)\r
-    exporter.write(filename, scene)\r
-\r
-\r
-if isBlender24():\r
-    # for 2.4\r
-    def execute_24(filename):\r
-        """\r
-        export mqo.\r
-        """\r
-        filename=filename.decode(bl.INTERNAL_ENCODING)\r
-        print("mqo exporter: %s" % filename)\r
-\r
-        Blender.Window.WaitCursor(1) \r
-        t = Blender.sys.time() \r
-\r
-        __execute(filename, Blender.Scene.GetCurrent())\r
-\r
-        print('finished in %.2f seconds' % (Blender.sys.time()-t) )\r
-        Blender.Redraw()\r
-        Blender.Window.WaitCursor(0) \r
-\r
-    # execute\r
-    Blender.Window.FileSelector(\r
-            execute_24, \r
-            'Export Metasequoia MQO', \r
-            Blender.sys.makename(ext='.mqo'))\r
-\r
-else:\r
-    # for 2.5\r
-    def execute_25(*args):\r
-        __execute(*args)\r
-\r
-    # operator\r
-    class EXPORT_OT_mqo(bpy.types.Operator):\r
-        '''Save a Metasequoia MQO file.'''\r
-        bl_idname = "export_scene.mqo"\r
-        bl_label = 'Export MQO'\r
-\r
-        # List of operator properties, the attributes will be assigned\r
-        # to the class instance from the operator settings before calling.\r
-\r
-        path = StringProperty(\r
-                name="File Path",\r
-                description="File path used for exporting the MQO file",\r
-                maxlen= 1024,\r
-                default= ""\r
-                )\r
-        filename = StringProperty(\r
-                name="File Name", \r
-                description="Name of the file.")\r
-        directory = StringProperty(\r
-                name="Directory", \r
-                description="Directory of the file.")\r
-\r
-        scale = FloatProperty(\r
-                name="Scale", \r
-                description="Scale the MQO by this value", \r
-                min=0.0001, max=1000000.0, \r
-                soft_min=0.001, soft_max=100.0, default=100.0)\r
-\r
-        check_existing = BoolProperty(\r
-                name="Check Existing",\r
-                description="Check and warn on overwriting existing files",\r
-                default=True,\r
-                options=set('HIDDEN'))\r
-\r
-        def execute(self, context):\r
-            execute_25(\r
-                    self.properties.path, \r
-                    context.scene, \r
-                    self.properties.scale)\r
-            return 'FINISHED'\r
-\r
-        def invoke(self, context, event):\r
-            wm=context.manager\r
-            wm.add_fileselect(self)\r
-            return 'RUNNING_MODAL'\r
-\r
-    # register menu\r
-    def menu_func(self, context): \r
-        #default_path=bpy.data.filename.replace(".blend", ".mqo")\r
-        self.layout.operator(\r
-                EXPORT_OT_mqo.bl_idname, \r
-                text="Metasequoia (.mqo)")#.path=default_path\r
-\r
-    def register():\r
-        bpy.types.register(EXPORT_OT_mqo)\r
-        bpy.types.INFO_MT_file_export.append(menu_func)\r
-\r
-    def unregister():\r
-        bpy.types.unregister(EXPORT_OT_mqo)\r
-        bpy.types.INFO_MT_file_export.remove(menu_func)\r
-\r
-    if __name__ == "__main__":\r
-        register()\r
-\r
+#!BPY
+# coding: utf-8
+
+"""
+Name: 'Metasequoia (.mqo)...'
+Blender: 245
+Group: 'Export'
+Tooltip: 'Save as Metasequoia MQO File'
+"""
+__author__= 'ousttrue'
+__url__ = ["http://gunload.web.fc2.com/blender/"]
+__version__= '2.0'
+__bpydoc__ = """\
+This script is an exporter to MQO file format.
+
+Usage:
+
+Run this script from "File->Export" menu.
+
+0.1 20080128:
+0.2 20100518: refactoring.
+0.3 20100606: integrate 2.4 and 2.5.
+0.4 20100626: refactoring.
+0.5 20100710: add [apply_modifier] option(2.5 only).
+0.6 20100714: remove shape_key when apply_modifier. fix material.
+2.0 20100724: update for Blender2.53.
+"""
+
+bl_addon_info = {
+        'category': 'Import/Export',
+        'name': 'Export: Metasequioa Model Format (.mqo)',
+        'author': 'ousttrue',
+        'version': '2.0',
+        'blender': (2, 5, 3),
+        'location': 'File > Export',
+        'description': 'Export to the Metasequioa Model Format (.mqo)',
+        'warning': '', # used for warning icon and text in addons panel
+        'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
+        }
+
+import os
+import sys
+
+def isBlender24():
+    return sys.version_info[0]<3
+
+
+class MQOMaterial(object):
+    __slots__=[
+            'name', 'shader', 'r', 'g', 'b', 'a',
+            'dif', 'amb', 'emi',
+            ]
+    def __init__(self, name, shader=3):
+        self.name=name
+        self.shader=shader
+        self.r=0.5
+        self.g=0.5
+        self.b=0.5
+        self.a=1
+        self.dif=1
+        self.amb=0
+        self.emi=0
+
+    def __str__(self):
+        return "\"%s\" shader(%d) col(%f %f %f %f) dif(%f) amb(%f) emi(%f)" % (
+                self.name, self.shader, self.r, self.g, self.b, self.a,
+                self.dif, self.amb, self.emi
+                )
+
+
+if isBlender24():
+    # for 2.4
+    import Blender
+    from Blender import Mathutils
+    import bpy
+
+    # wrapper
+    import bl24 as bl
+
+    def materialToMqo(m):
+        material=MQOMaterial(m.name, 3)
+        material.r=m.rgbCol[0]
+        material.g=m.rgbCol[1]
+        material.b=m.rgbCol[2]
+        material.a=m.alpha
+        return material
+
+else:
+    # for 2.5
+    import bpy
+
+    # wrapper
+    import bl25 as bl
+
+    def materialToMqo(m):
+        material=MQOMaterial(m.name, 3)
+        material.r=m.diffuse_color[0]
+        material.g=m.diffuse_color[1]
+        material.b=m.diffuse_color[2]
+        material.a=m.alpha
+        material.amb=m.ambient
+        material.emi=m.emit
+        return material
+
+def apply_transform(vec, matrix):
+    x, y, z = vec
+    xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
+    return    x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\
+            x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\
+            x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
+
+def convert_to_mqo(vec):
+    return vec.x, vec.z, -vec.y
+
+
+class OutlineNode(object):
+    __slots__=['o', 'children']
+    def __init__(self, o):
+        self.o=o
+        self.children=[]
+
+    def __str__(self):
+        return "<Node %s>" % self.o
+
+
+class ObjectInfo(object):
+    __slots__=['object', 'depth', 'material_map']
+    def __init__(self, o, depth):
+        self.object=o
+        self.depth=depth
+        self.material_map={}
+
+    def __str__(self):
+        return "<ObjectInfo %d %s>" % (self.depth, self.object)
+
+
+class MqoExporter(object):
+    __slots__=["materials", "objects", 'scale', 'apply_modifier',]
+    def __init__(self, scale, apply_modifier):
+        self.objects=[]
+        self.materials=[]
+        self.scale=scale
+        self.apply_modifier=apply_modifier
+
+    def setup(self, scene):
+        # 木構造を構築する
+        object_node_map={}
+        for o in scene.objects:
+            object_node_map[o]=OutlineNode(o)
+        for node in object_node_map.values():
+            if node.o.parent:
+                object_node_map[node.o.parent].children.append(node)
+
+        # ルートを得る
+        root=object_node_map[scene.objects.active]
+
+        # 情報を集める
+        if root.o.type.upper()=='EMPTY':
+            # depth調整 
+            for node in root.children:
+                self.__setup(node)
+        else:
+            self.__setup(root)
+
+    def __setup(self, node, depth=0):
+        info=ObjectInfo(node.o, depth)
+        self.objects.append(info)
+        if node.o.type.upper()=='MESH':
+            # set material index
+            for i, m in enumerate(node.o.data.materials):
+                info.material_map[i]=self.__getOrAddMaterial(m)
+        # recursive
+        for child in node.children:
+            self.__setup(child, depth+1)
+            
+    def __getOrAddMaterial(self, material):
+        for i, m in enumerate(self.materials):
+            if m==material:
+                return i
+        index=len(self.materials)
+        self.materials.append(material)
+        return index
+
+    def write(self, path):
+        bl.message("open: "+path)
+        io=bl.Writer(path, 'cp932')
+        self.__write_header(io)
+        self.__write_scene(io)
+        print("Writing MaterialChunk")
+        self.__write_materials(io, os.path.dirname(path))
+        print("Writing ObjectChunk")
+        for info in self.objects:
+            self.__write_object(io, info)
+        io.write("Eof\r\n")
+        io.flush()
+        io.close()
+
+    def __write_header(self, io):
+        io.write("Metasequoia Document\r\n")
+        io.write("Format Text Ver 1.0\r\n")
+        io.write("\r\n")
+
+    def __write_scene(self, io):
+        print("Writing SceneChunk")
+        io.write("Scene {\r\n")
+        io.write("}\r\n")
+
+    def __write_materials(self, io, dirname):
+        # each material    
+        io.write("Material %d {\r\n" % (len(self.materials)))
+        for m in self.materials:
+            io.write(str(materialToMqo(m)))
+            # ToDo separated alpha texture
+            for filename in bl.material.eachTexturePath(m):
+                if len(dirname)>0 and filename.startswith(dirname):
+                    # 相対パスに変換する
+                    filename=filename[len(dirname)+1:]
+                io.write(" tex(\"%s\")" % filename)
+                break
+            io.write("\r\n") 
+        # end of chunk
+        io.write("}\r\n") 
+
+    def __write_object(self, io, info):
+        print(info)
+
+        obj=info.object
+        if obj.type.upper()=='MESH' or obj.type.upper()=='EMPTY':
+            pass
+        else:
+            print(obj.type)
+            return
+
+        io.write("Object \""+obj.name+"\" {\r\n")
+
+        # depth
+        io.write("\tdepth %d\r\n" % info.depth)
+
+        # mirror
+        if not self.apply_modifier:
+            if bl.modifier.hasType(obj, 'MIRROR'):
+                    io.write("\tmirror 1\r\n")
+                    io.write("\tmirror_axis 1\r\n")
+
+        if obj.type.upper()=='MESH':
+            # duplicate and applyMatrix
+            copyMesh, copyObj=bl.object.duplicate(obj)
+            # apply transform
+            copyObj.scale=obj.scale
+            bpy.ops.object.scale_apply()
+            copyObj.rotation_euler=obj.rotation_euler
+            bpy.ops.object.rotation_apply()
+            copyObj.location=obj.location
+            bpy.ops.object.location_apply()
+            # apply modifier
+            if self.apply_modifier:
+                # remove shape key
+                while bl.object.hasShapeKey(copyObj):
+                    bpy.ops.object.shape_key_remove()
+                for m in [m for m in copyObj.modifiers]:
+                    if m.type=='SOLIDFY':
+                        continue
+                    elif m.type=='ARMATURE':
+                        bpy.ops.object.modifier_apply(modifier=m.name)
+                    elif m.type=='MIRROR':
+                        bpy.ops.object.modifier_apply(modifier=m.name)
+                    else:
+                        print(m.type)
+            # write mesh
+            self.__write_mesh(io, copyMesh, info.material_map)
+            bl.object.delete(copyObj)
+
+        io.write("}\r\n") # end of object
+
+    def __write_mesh(self, io, mesh, material_map):
+        # vertices
+        io.write("\tvertex %d {\r\n" % len(mesh.verts))
+        for vert in mesh.verts:
+            x, y, z = convert_to_mqo(vert.co)
+            io.write("\t\t%f %f %f\r\n" % 
+                    (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up
+        io.write("\t}\r\n")
+
+        # faces
+        io.write("\tface %d {\r\n" % len(mesh.faces))
+        for i, face in enumerate(mesh.faces):
+            count=bl.face.getVertexCount(face)
+            # V
+            io.write("\t\t%d V(" % count)
+            for j in reversed(bl.face.getVertices(face)):
+                io.write("%d " % j)
+            io.write(")")
+            # mat
+            if len(mesh.materials):
+                io.write(" M(%d)" % 
+                        material_map[bl.face.getMaterialIndex(face)])
+            # UV
+            if bl.mesh.hasUV(mesh) and bl.mesh.hasFaceUV(mesh, i, face):
+                io.write(" UV(")
+                for uv in reversed(bl.mesh.getFaceUV(mesh, i, face, count)):
+                    # reverse vertical value
+                    io.write("%f %f " % (uv[0], 1.0-uv[1])) 
+                io.write(")")
+            io.write("\r\n")
+        io.write("\t}\r\n") # end of faces
+
+
+def __execute(filename, scene, scale=10, apply_modifier=False):
+    if scene.objects.active:
+        exporter=MqoExporter(scale, apply_modifier)
+        exporter.setup(scene)
+        exporter.write(filename)
+    else:
+        bl.message('no active object !')
+
+
+if isBlender24():
+    # for 2.4
+    def execute_24(filename):
+        scene=Blender.Scene.GetCurrent()
+        bl.initialize('mqo_export', scene)
+        __execute(
+                filename.decode(bl.INTERNAL_ENCODING), 
+                scene, False)
+        bl.finalize()
+
+    # execute
+    Blender.Window.FileSelector(
+            execute_24, 
+            'Export Metasequoia MQO', 
+            Blender.sys.makename(ext='.mqo'))
+
+else:
+    # for 2.5
+    def execute_25(path, scene, scale, apply_modifier):
+        bl.initialize('mqo_export', scene)
+        __execute(path, scene, scale, apply_modifier)
+        bl.finalize()
+
+    # operator
+    class EXPORT_OT_mqo(bpy.types.Operator):
+        '''Save a Metasequoia MQO file.'''
+        bl_idname = "export_scene.mqo"
+        bl_label = 'Export MQO'
+
+        # List of operator properties, the attributes will be assigned
+        # to the class instance from the operator settings before calling.
+        filepath = bpy.props.StringProperty()
+        filename = bpy.props.StringProperty()
+        directory = bpy.props.StringProperty()
+
+        scale = bpy.props.FloatProperty(
+                name="Scale", 
+                description="Scale the MQO by this value", 
+                min=0.0001, max=1000000.0, 
+                soft_min=0.001, soft_max=100.0, default=10.0)
+
+        apply_modifier = bpy.props.BoolProperty(
+                name="ApplyModifier", 
+                description="Would apply modifiers", 
+                default=False)
+
+        def execute(self, context):
+            execute_25(
+                    self.properties.filepath, 
+                    context.scene, 
+                    self.properties.scale,
+                    self.properties.apply_modifier)
+            return 'FINISHED'
+
+        def invoke(self, context, event):
+            wm=context.manager
+            wm.add_fileselect(self)
+            return 'RUNNING_MODAL'
+
+    # register menu
+    def menu_func(self, context): 
+        default_path=bpy.data.filepath.replace(".blend", ".mqo")
+        self.layout.operator(
+                EXPORT_OT_mqo.bl_idname, 
+                text="Metasequoia (.mqo)",
+                icon='PLUGIN'
+                ).filepath=default_path
+
+    def register():
+        bpy.types.register(EXPORT_OT_mqo)
+        bpy.types.INFO_MT_file_export.append(menu_func)
+
+    def unregister():
+        bpy.types.unregister(EXPORT_OT_mqo)
+        bpy.types.INFO_MT_file_export.remove(menu_func)
+
+    if __name__ == "__main__":
+        register()
+