OSDN Git Service

fix mqo hierarchy. fix pmd constraint name.
[meshio/meshio.git] / swig / blender / mqo_export.py
1 #!BPY\r
2 # coding: utf-8\r
3 \r
4 """\r
5 Name: 'Metasequoia (.mqo)...'\r
6 Blender: 245\r
7 Group: 'Export'\r
8 Tooltip: 'Save as Metasequoia MQO File'\r
9 """\r
10 __author__= 'ousttrue'\r
11 __url__ = ["http://gunload.web.fc2.com/blender/"]\r
12 __version__= '0.3 2010/06/06'\r
13 __bpydoc__ = """\\r
14 This script is an exporter to MQO file format.\r
15 \r
16 Usage:\r
17 \r
18 Run this script from "File->Export" menu.\r
19 \r
20 0.1 20080128:\r
21 0.2 20100518: refactoring.\r
22 0.3 20100606: integrate 2.4 and 2.5.\r
23 """\r
24 \r
25 \r
26 ###############################################################################\r
27 # import\r
28 ###############################################################################\r
29 import os\r
30 import sys\r
31 \r
32 def isBlender24():\r
33     return sys.version_info[0]<3\r
34 \r
35 if isBlender24():\r
36     # for 2.4\r
37     import Blender\r
38     from Blender import Mathutils\r
39     import bpy\r
40 \r
41     # wrapper\r
42     import bl24 as bl\r
43 \r
44 else:\r
45     # for 2.5\r
46     import bpy\r
47     from bpy.props import *\r
48 \r
49     # wrapper\r
50     import bl25 as bl\r
51 \r
52 def apply_transform(vec, matrix):\r
53     x, y, z = vec\r
54     xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]\r
55     return    x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\\r
56             x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\\r
57             x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc\r
58 \r
59 def convert_to_mqo(vec):\r
60     return vec.x, vec.z, -vec.y\r
61 \r
62 \r
63 class OutlineNode(object):\r
64     __slots__=['o', 'children']\r
65     def __init__(self, o):\r
66         self.o=o\r
67         self.children=[]\r
68 \r
69     def __str__(self):\r
70         return "<Node %s>" % self.o\r
71 \r
72 \r
73 class ObjectInfo(object):\r
74     __slots__=['object', 'depth', 'material_map']\r
75     def __init__(self, o, depth):\r
76         self.object=o\r
77         self.depth=depth\r
78         self.material_map={}\r
79 \r
80     def __str__(self):\r
81         return "<ObjectInfo %d %s>" % (self.depth, self.object)\r
82 \r
83 \r
84 class MqoExporter(object):\r
85     __slots__=["materials", "objects", 'scale',]\r
86     def __init__(self, scale):\r
87         self.objects=[]\r
88         self.materials=[]\r
89         self.scale=scale\r
90         print('scaling', self.scale)\r
91 \r
92     def setup(self, scene):\r
93         # 木構造を構築する\r
94         object_node_map={}\r
95         for o in scene.objects:\r
96             object_node_map[o]=OutlineNode(o)\r
97         for node in object_node_map.values():\r
98             if node.o.parent:\r
99                 object_node_map[node.o.parent].children.append(node)\r
100 \r
101         # ルートを得る\r
102         root=object_node_map[scene.objects.active]\r
103 \r
104         # 情報を集める\r
105         if root.o.type.upper()=='EMPTY':\r
106             # depth調整 \r
107             for node in root.children:\r
108                 self.__setup(node)\r
109         else:\r
110             self.__setup(root)\r
111 \r
112     def __setup(self, node, depth=0):\r
113         info=ObjectInfo(node.o, depth)\r
114         self.objects.append(info)\r
115         if node.o.type.upper()=='MESH':\r
116             # set material index\r
117             for i, m in enumerate(node.o.data.materials):\r
118                 info.material_map[i]=self.__getOrAddMaterial(m)\r
119         # recursive\r
120         for child in node.children:\r
121             self.__setup(child, depth+1)\r
122             \r
123     def __getOrAddMaterial(self, material):\r
124         for i, m in enumerate(self.materials):\r
125             if m==material:\r
126                 return i\r
127         index=len(self.materials)\r
128         self.materials.append(material)\r
129         return index\r
130 \r
131     def write(self, path, scene):\r
132         io=bl.Writer(path, 'cp932')\r
133         self.__write_header(io)\r
134         self.__write_scene(io)\r
135         print("Writing MaterialChunk")\r
136         self.__write_materials(io, os.path.dirname(path))\r
137         print("Writing ObjectChunk")\r
138         for info in self.objects:\r
139             self.__write_object(io, info, scene)\r
140         io.write("Eof\r\n")\r
141         io.flush()\r
142         io.close()\r
143 \r
144     def __write_header(self, io):\r
145         io.write("Metasequoia Document\r\n")\r
146         io.write("Format Text Ver 1.0\r\n")\r
147         io.write("\r\n")\r
148 \r
149     def __write_scene(self, io):\r
150         print("Writing SceneChunk")\r
151         io.write("Scene {\r\n")\r
152         io.write("}\r\n")\r
153 \r
154     def __write_materials(self, io, dirname):\r
155         # each material    \r
156         io.write("Material %d {\r\n" % (len(self.materials)))\r
157         for m in self.materials:\r
158             tex, aplane=bl.getTexture(m, dirname)\r
159             if len(tex):\r
160                 # textureがある場合は下地を白に\r
161                 io.write("\"%s\" shader(3) col(1 1 1 1)" % m.name)\r
162             else:\r
163                 # 無い場合はそのまま\r
164                 io.write(bl.materialToMqo(m))\r
165             io.write(tex)\r
166             io.write(aplane)\r
167             io.write("\r\n") \r
168         # end of chunk\r
169         io.write("}\r\n") \r
170 \r
171     def __write_object(self, io, info, scene):\r
172         print(info)\r
173 \r
174         obj=info.object\r
175         if obj.type.upper()=='MESH' or obj.type.upper()=='EMPTY':\r
176             pass\r
177         else:\r
178             print(obj.type)\r
179             return\r
180 \r
181         ############################################################\r
182         # write\r
183         ############################################################\r
184         io.write("Object \""+obj.name+"\" {\r\n")\r
185 \r
186         # depth\r
187         io.write("\tdepth %d\r\n" % info.depth)\r
188 \r
189         # mirroring                \r
190         isMirrorring=False\r
191         for mod in obj.modifiers:\r
192                 if mod.name.upper()=="MIRROR":\r
193                         isMirrorring=True\r
194                         break\r
195         if isMirrorring:\r
196                 io.write("\tmirror 1\r\n")\r
197                 io.write("\tmirror_axis 1\r\n")\r
198 \r
199         if obj.type.upper()=='MESH':\r
200             # duplicate and applyMatrix\r
201             mesh, dumy=bl.objectDuplicate(scene, obj)\r
202 \r
203             # vertices\r
204             io.write("\tvertex %d {\r\n" % len(mesh.verts))\r
205             for vert in mesh.verts:\r
206                 x, y, z = convert_to_mqo(vert.co)\r
207                 io.write("\t\t%f %f %f\r\n" % \r
208                         (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up\r
209             io.write("\t}\r\n")\r
210 \r
211             # faces\r
212             io.write("\tface %d {\r\n" % len(mesh.faces))\r
213             for i, face in enumerate(mesh.faces):\r
214                 count=bl.faceVertexCount(face)\r
215                 # V\r
216                 io.write("\t\t%d V(" % count)\r
217                 face_list=[]\r
218                 for j in bl.faceVertices(face):\r
219                     face_list.insert(0, j)\r
220                 # flip face\r
221                 for j in face_list:\r
222                     io.write("%d " % j)\r
223                 io.write(")")\r
224                 # mat\r
225                 if len(mesh.materials):\r
226                     io.write(" M(%d)" % \r
227                             info.material_map[bl.faceMaterialIndex(face)])\r
228                 # UV\r
229                 if bl.meshHasUV(mesh) and bl.faceHasUV(mesh, i, face):\r
230                     io.write(" UV(")\r
231                     uv_list=[]\r
232                     for uv in bl.faceGetUV(mesh, i, face, count):\r
233                         # reverse vertical value\r
234                         uv_list.insert(0, uv)\r
235                     # flip face\r
236                     for uv in uv_list:\r
237                         io.write("%f %f " % (uv[0], 1.0-uv[1])) \r
238                     io.write(")")\r
239                 io.write("\r\n")\r
240             io.write("\t}\r\n") # end of faces\r
241 \r
242             # 削除する\r
243             scene.objects.unlink(dumy)\r
244 \r
245         io.write("}\r\n") # end of object\r
246 \r
247 \r
248 def __execute(filename, scene, scale=10):\r
249     exporter=MqoExporter(scale)\r
250     exporter.setup(scene)\r
251     exporter.write(filename, scene)\r
252 \r
253 \r
254 if isBlender24():\r
255     # for 2.4\r
256     def execute_24(filename):\r
257         """\r
258         export mqo.\r
259         """\r
260         filename=filename.decode(bl.INTERNAL_ENCODING)\r
261         print("mqo exporter: %s" % filename)\r
262 \r
263         Blender.Window.WaitCursor(1) \r
264         t = Blender.sys.time() \r
265 \r
266         __execute(filename, Blender.Scene.GetCurrent())\r
267 \r
268         print('finished in %.2f seconds' % (Blender.sys.time()-t) )\r
269         Blender.Redraw()\r
270         Blender.Window.WaitCursor(0) \r
271 \r
272     # execute\r
273     Blender.Window.FileSelector(\r
274             execute_24, \r
275             'Export Metasequoia MQO', \r
276             Blender.sys.makename(ext='.mqo'))\r
277 \r
278 else:\r
279     # for 2.5\r
280     def execute_25(*args):\r
281         __execute(*args)\r
282 \r
283     # operator\r
284     class EXPORT_OT_mqo(bpy.types.Operator):\r
285         '''Save a Metasequoia MQO file.'''\r
286         bl_idname = "export_scene.mqo"\r
287         bl_label = 'Export MQO'\r
288 \r
289         # List of operator properties, the attributes will be assigned\r
290         # to the class instance from the operator settings before calling.\r
291 \r
292         path = StringProperty(\r
293                 name="File Path",\r
294                 description="File path used for exporting the MQO file",\r
295                 maxlen= 1024,\r
296                 default= ""\r
297                 )\r
298         filename = StringProperty(\r
299                 name="File Name", \r
300                 description="Name of the file.")\r
301         directory = StringProperty(\r
302                 name="Directory", \r
303                 description="Directory of the file.")\r
304 \r
305         scale = FloatProperty(\r
306                 name="Scale", \r
307                 description="Scale the MQO by this value", \r
308                 min=0.0001, max=1000000.0, \r
309                 soft_min=0.001, soft_max=100.0, default=100.0)\r
310 \r
311         check_existing = BoolProperty(\r
312                 name="Check Existing",\r
313                 description="Check and warn on overwriting existing files",\r
314                 default=True,\r
315                 options=set('HIDDEN'))\r
316 \r
317         def execute(self, context):\r
318             execute_25(\r
319                     self.properties.path, \r
320                     context.scene, \r
321                     self.properties.scale)\r
322             return 'FINISHED'\r
323 \r
324         def invoke(self, context, event):\r
325             wm=context.manager\r
326             wm.add_fileselect(self)\r
327             return 'RUNNING_MODAL'\r
328 \r
329     # register menu\r
330     def menu_func(self, context): \r
331         #default_path=bpy.data.filename.replace(".blend", ".mqo")\r
332         self.layout.operator(\r
333                 EXPORT_OT_mqo.bl_idname, \r
334                 text="Metasequoia (.mqo)")#.path=default_path\r
335 \r
336     def register():\r
337         bpy.types.register(EXPORT_OT_mqo)\r
338         bpy.types.INFO_MT_file_export.append(menu_func)\r
339 \r
340     def unregister():\r
341         bpy.types.unregister(EXPORT_OT_mqo)\r
342         bpy.types.INFO_MT_file_export.remove(menu_func)\r
343 \r
344     if __name__ == "__main__":\r
345         register()\r
346 \r