OSDN Git Service

pmd. sort material order.
[meshio/meshio.git] / swig / blender24 / 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__= '1.0 2008/01/28'\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 """\r
23 \r
24 import Blender\r
25 import os\r
26 import sys\r
27 \r
28 \r
29 EXTENSION = u'.mqo'\r
30 \r
31 \r
32 # ファイルシステムの文字コード\r
33 # 改造版との共用のため\r
34 FS_ENCODING=sys.getfilesystemencoding()\r
35 if os.path.exists(os.path.dirname(sys.argv[0])+"/utf8"):\r
36         INTERNAL_ENCODING='utf-8'\r
37 else:\r
38         INTERNAL_ENCODING=FS_ENCODING\r
39 \r
40 \r
41 class OutlineNode(object):\r
42     __slots__=['o', 'children']\r
43     def __init__(self, o):\r
44         self.o=o\r
45         self.children=[]\r
46 \r
47 \r
48 class ObjectInfo(object):\r
49     __slots__=['object', 'depth', 'material_map']\r
50     def __init__(self, o, depth):\r
51         self.object=o\r
52         self.depth=depth\r
53         self.material_map={}\r
54 \r
55 \r
56 class MqoExporter(object):\r
57     __slots__=["materials", "objects"]\r
58     def setup(self, scene):\r
59         # 木構造を構築する\r
60         object_node_map={}\r
61         for o in scene.objects:\r
62             object_node_map[o]=OutlineNode(o)\r
63         for node in object_node_map.values():\r
64             if node.o.parent:\r
65                 object_node_map[node.o.parent].children.append(node)\r
66 \r
67         # ルートを得る\r
68         root=object_node_map[scene.objects.active]\r
69 \r
70         # 情報を集める\r
71         self.objects=[]\r
72         self.materials=[]\r
73         if root.o.getType()=='Empty':\r
74             for child in root.children:\r
75                 self.__setup(child)\r
76         else:\r
77             self.__setup(root)\r
78 \r
79     def __setup(self, parent, depth=0):\r
80         if parent.o.getType()=='Mesh':\r
81             info=ObjectInfo(parent.o, depth)\r
82             self.objects.append(info)\r
83             # set material index\r
84             for i, m in enumerate(parent.o.data.materials):\r
85                 info.material_map[i]=self.__getOrAddMaterial(m)\r
86         # recursive\r
87         for child in parent.children:\r
88             __setup(child, depth+1)\r
89             \r
90     def __getOrAddMaterial(self, material):\r
91         for i, m in enumerate(self.materials):\r
92             if m==material:\r
93                 return i\r
94         index=len(self.materials)\r
95         self.materials.append(material)\r
96         return index\r
97 \r
98     def write(self, path):\r
99         io=open(path, "wb")\r
100         self.__write_header(io)\r
101         self.__write_scene(io)\r
102         print "Writing MaterialChunk"\r
103         self.__write_materials(io, os.path.dirname(path))\r
104         print "Writing ObjectChunk"\r
105         for info in self.objects:\r
106             self.__write_object(io, info)\r
107         io.write("Eof\r\n")\r
108         io.flush()\r
109         io.close()\r
110 \r
111     def __write_header(self, io):\r
112         io.write("Metasequoia Document\r\n")\r
113         io.write("Format Text Ver 1.0\r\n")\r
114         io.write("\r\n")\r
115 \r
116     def __write_scene(self, io):\r
117         print "Writing SceneChunk"\r
118         io.write("Scene {\r\n")\r
119         io.write("}\r\n")\r
120 \r
121     def __write_materials(self, io, dirname):\r
122         # each material    \r
123         io.write("Material %d {\r\n" % (len(self.materials)))\r
124         for m in self.materials:\r
125             texture=""\r
126             aplane=""\r
127             # texture\r
128             for mtex in m.getTextures():\r
129                 if mtex and mtex.tex and mtex.tex.getImage():\r
130                     image=mtex.tex.getImage()\r
131                     if not image:\r
132                         continue\r
133                     imagePath=Blender.sys.expandpath(image.getFilename())\r
134                     if len(dirname) and imagePath.startswith(dirname):\r
135                         # 相対パスに変換する\r
136                         imagePath=imagePath[len(dirname)+1:len(imagePath)]\r
137                     #imagePath=Blender.sys.expandpath(\r
138                     #        imagePath).replace("\\", '/')\r
139                     if mtex.mtCol:\r
140                         texture=" tex(\"%s\")" % imagePath\r
141                     elif mtex.mtAlpha:\r
142                         aplane=" aplane(\"%s\")" % imagePath\r
143             if len(texture):\r
144                 # textureがある場合は下地を白に\r
145                 io.write("\"%s\" shader(3) col(1 1 1 1)" % m.name)\r
146             else:\r
147                 # 無い場合はそのまま\r
148                 io.write("\"%s\" shader(3) col(%f %f %f %f)" % (\r
149                     m.name, \r
150                     m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha))\r
151             io.write(texture)\r
152             io.write(aplane)\r
153             io.write("\r\n") \r
154         # end of chunk\r
155         io.write("}\r\n") \r
156 \r
157     def __write_object(self, io, info, depth=0):\r
158         obj=info.object\r
159         if obj.getType() != 'Mesh':\r
160             return\r
161         mesh=Blender.Mesh.New()\r
162         dumy = Blender.Object.New("Mesh", "dumy")\r
163         # not apply modifiers\r
164         mesh.getFromObject(obj.name, 1)\r
165         dumy.link(mesh)\r
166         # apply matrix\r
167         dumy.setMatrix(obj.matrixWorld)\r
168         # link\r
169         scene=Blender.Scene.GetCurrent()\r
170         scene.objects.link(dumy)\r
171 \r
172         ############################################################\r
173         # write\r
174         ############################################################\r
175         io.write("Object \""+obj.name+"\" {\r\n")\r
176 \r
177         # 座標系をmqo(right-handed y-up)に変換する\r
178         # global matrix\r
179         matrix=obj.matrixWorld\r
180         # rotate to y-up\r
181         matrix*=Blender.Mathutils.RotationMatrix(-90, 4, 'x')\r
182         # scale\r
183         #matrix*=Blender.Mathutils.ScaleMatrix(SCALING_FACOR, 4)\r
184 \r
185         # depth\r
186         io.write("\tdepth %d\r\n" % depth)\r
187 \r
188         # mirroring                \r
189         isMirrorring=False\r
190         for mod in obj.modifiers:\r
191                 if mod.name=="Mirror":\r
192                         isMirrorring=True\r
193                         break\r
194         if isMirrorring:\r
195                 io.write("\tmirror 1\r\n")\r
196                 io.write("\tmirror_axis 1\r\n")\r
197 \r
198         mesh=Blender.Mesh.New()\r
199         ############################################################\r
200         # not applied modifiers\r
201         ############################################################\r
202         mesh.getFromObject(obj.name, 1)\r
203 \r
204         # vertices\r
205         io.write("\tvertex %d {\r\n" % len(mesh.verts))\r
206         for vert in mesh.verts:\r
207             x, y, z = apply_transform(vert.co, matrix)\r
208             io.write("\t\t%f %f %f\r\n" % (x, y, z)) # 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 face in mesh.faces:\r
214             poly_cnt = len(face.v)\r
215             # V\r
216             verts =list(face.v)\r
217             io.write("\t\t%d V(" % poly_cnt)\r
218             for i in reversed(range(poly_cnt)): # reverse normal\r
219                 io.write("%d " % verts[i].index)\r
220             io.write(")")\r
221             # mat\r
222             if len(mesh.materials):\r
223                 try:\r
224                     io.write(" M(%d)" % info.material_map[face.mat])\r
225                 except:\r
226                     #print(info.material_map, face.mat)\r
227                     pass\r
228             # UV\r
229             if mesh.faceUV:\r
230                 uv = list(face.uv)\r
231                 if len(uv)>0:\r
232                     io.write(" UV(")\r
233                     # reverse normal\r
234                     for i in reversed(range(poly_cnt)): \r
235                         # reverse V\r
236                         io.write("%f %f " % (uv[i][0], 1.0-uv[i][1])) \r
237                     io.write(")")\r
238             io.write("\r\n")\r
239         io.write("\t}\r\n") # end of faces\r
240         io.write("}\r\n") # end of object\r
241         ############################################################\r
242 \r
243         # 削除する\r
244         scene.objects.unlink(dumy)\r
245 \r
246 \r
247 def export_mqo(fileName):\r
248     """\r
249     export mqo.\r
250     """\r
251     fileName=fileName.decode(INTERNAL_ENCODING)\r
252 \r
253     Blender.Window.WaitCursor(1) \r
254     t = Blender.sys.time() \r
255 \r
256     if not fileName.lower().endswith(EXTENSION):\r
257         fileName += EXTENSION\r
258     print "mqo exporter: %s" % fileName\r
259 \r
260     exporter=MqoExporter()\r
261 \r
262     # 情報収集\r
263     exporter.setup(Blender.Scene.GetCurrent())\r
264 \r
265     # 出力\r
266     exporter.write(fileName)\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 def apply_transform(vec, matrix):\r
273     x, y, z = vec\r
274     xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]\r
275     return    x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\\r
276             x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\\r
277             x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc\r
278 \r
279 \r
280 Blender.Window.FileSelector(\r
281         export_mqo, \r
282         'Export Metasequoia MQO', \r
283         Blender.sys.makename(ext=EXTENSION))\r
284 \r