OSDN Git Service

add swig python extension.
[meshio/meshio.git] / blender24 / mqo_export.py
1 #!BPY\r
2 \r
3 """\r
4 Name: 'Metasequoia (.mqo)...'\r
5 Blender: 245\r
6 Group: 'Export'\r
7 Submenu: 'All meshes...' all\r
8 Submenu: 'Only selected meshes...' selected\r
9 Submenu: 'All meshes(join)...' alljoined\r
10 Submenu: 'Only selected(join)...' seljoined\r
11 Submenu: 'Active Object Hierarchy...' hierarchy\r
12 Tooltip: 'Save as Metasequoia MQO File'\r
13 """\r
14 __author__= 'ousttrue'\r
15 __url__ = ["http://gunload.web.fc2.com/blender/"]\r
16 __version__= '1.0 2008/01/28'\r
17 __bpydoc__ = """\\r
18 This script is an exporter to MQO file format.\r
19 \r
20 Usage:\r
21 \r
22 Run this script from "File->Export" menu.\r
23 """\r
24 \r
25 # LICENSE (BSD Style)\r
26 #\r
27 # Redistribution and use in source and binary forms, with or without \r
28 # modification, are permitted provided that the following conditions \r
29 # are met:\r
30 #  * Redistributions of source code must retain the above copyright \r
31 #   notice, this list of conditions and the following disclaimer.\r
32 #  * Redistributions in binary form must reproduce the above \r
33 #   copyright notice, this list of conditions and the following \r
34 #   disclaimer in the documentation and/or other materials provided \r
35 #   with the distribution.\r
36 #  * Neither the name of the <ORGANIZATION> nor the names of its \r
37 #   contributors may be used to endorse or promote products derived \r
38 #   from this software without specific prior written permission.\r
39 #\r
40 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
41 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
42 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR \r
43 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
44 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
45 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
46 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, \r
47 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY \r
48 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
49 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
50 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
51 \r
52 # ChangeLog\r
53 # 1.0 2008/01/28\r
54 #   rewrite. implement object hierarchy\r
55 \r
56 #--IMPORT\r
57 import Blender\r
58 import os\r
59 \r
60 FS_ENCODING='cp932'\r
61 \r
62 #--CONST\r
63 ARG = __script__['arg'] # user selected argument\r
64 EVENT_SHOWMENU = 0\r
65 EVENT_EXIT   = 1\r
66 EVENT_EXPORT  = 2\r
67 MQO_EXT = '.mqo'\r
68 \r
69 #--VAR\r
70 SCALING_FACOR=100 # scaling factor\r
71 \r
72 #--DEF\r
73 class Node(object):\r
74   __slots__=['name', 'children']\r
75   def __init__(self, name="__scene__"):\r
76     self.name=name\r
77     self.children=[]\r
78 \r
79   def addChild(self, child):\r
80     self.children.append(child)\r
81     \r
82   def printTree(self, level=0):\r
83     print " " * (level*2) + self.name\r
84     for child in self.children:\r
85       child.printTree(level+1)\r
86 \r
87 class NodeIterator(object):\r
88   __slots__=["list", "index"]\r
89   def __init__(self, node):\r
90     self.list=[]\r
91     self.setup(node)\r
92     self.index=0\r
93 \r
94   def setup(self, node):\r
95     self.list.append(node)\r
96     for child in node.children:  \r
97       self.setup(child)\r
98 \r
99   def __iter__(self):\r
100     return self\r
101   \r
102   def next(self):\r
103     if self.index<len(self.list): \r
104       node=self.list[self.index]\r
105       self.index+=1\r
106       return node\r
107     else:\r
108       raise StopIteration\r
109    \r
110 class SceneGraph(object):\r
111   __slots__=["root", "dict"]\r
112   def __init__(self):\r
113     self.root=Node()\r
114     self.dict={}\r
115 \r
116   def addObject(self, object):\r
117     # already added\r
118     if object.name in self.dict:\r
119       return\r
120 \r
121     parent=object.getParent()\r
122     node=Node(object.name)\r
123     if parent:\r
124       if not parent.name in self.dict:\r
125         addNode(self.dict, parent)\r
126       self.dict[parent.name].addChild(node)\r
127     else:\r
128       self.root.addChild(node)\r
129     self.dict[object.name]=node\r
130 \r
131   def get(self, name):\r
132     if name in self.dict:\r
133       return self.dict[name]\r
134     else:\r
135       return None\r
136 \r
137 class MqoExporter(object):\r
138   __slots__=["filename", "io", "objs", "materials", "isJoin"]\r
139   def __init__(self, filename):\r
140     self.filename=filename\r
141 \r
142   def do(self, objs, isJoin=False):\r
143     self.objs=objs\r
144     self.isJoin=isJoin\r
145     self.io=open(self.filename, "w")\r
146     self.write_header()\r
147     self.write_materials()\r
148     self.write_objects()\r
149     self.io.flush()\r
150     self.io.close()\r
151 \r
152   def do_hierarchy(self, node):\r
153     self.isJoin=False\r
154     self.objs=[Blender.Object.Get(x.name) for x in NodeIterator(node)]\r
155     self.io=open(self.filename, "w")\r
156     self.write_header()\r
157     self.write_materials()\r
158     self.write_objects_hierarchical(node)\r
159     self.io.flush()\r
160     self.io.close()\r
161 \r
162   def write_header(self):\r
163     self.io.write("Metasequoia Document\n")\r
164     self.io.write("Format Text Ver 1.0\n")\r
165     self.io.write("\n")\r
166 \r
167   def write_materials(self):\r
168     print "Writing MaterialChunk"\r
169     dirname=os.path.dirname(self.filename)\r
170     # used materials\r
171     materials=set()\r
172     # each object\r
173     for obj in self.objs:\r
174       if obj.getType() != 'Mesh':\r
175         continue\r
176       for mat in obj.getData(mesh=1).materials:\r
177         if mat:\r
178           materials.add(mat.name)\r
179     # each material  \r
180     self.materials=list(materials)\r
181     self.materials.sort()\r
182     self.io.write("Material %d {\n" % (len(self.materials)))\r
183     for material_name in self.materials:\r
184       m=Blender.Material.Get(material_name)\r
185       tex=""\r
186       aplane=""\r
187       # texture\r
188       for mtex in m.getTextures():\r
189         if mtex and mtex.tex and mtex.tex.getImage():\r
190           image=mtex.tex.getImage()\r
191           if not image:\r
192             continue\r
193           imagePath=Blender.sys.expandpath(image.getFilename())\r
194           if len(dirname) and imagePath.startswith(dirname):\r
195             imagePath=imagePath[len(dirname)+1:len(imagePath)]\r
196           imagePath=Blender.sys.expandpath(imagePath).replace("\\", '/')\r
197           if mtex.mtCol:\r
198             tex=" tex(\"%s\")" % imagePath\r
199           elif mtex.mtAlpha:\r
200             aplane=" aplane(\"%s\")" % imagePath\r
201       if len(tex):\r
202         self.io.write("\"%s\" shader(3) col(1 1 1 1)" % material_name)\r
203       else:\r
204         self.io.write("\"%s\" shader(3) col(%f %f %f %f)" % (material_name, m.rgbCol[0], m.rgbCol[1], m.rgbCol[2], m.alpha))\r
205       self.io.write(tex)\r
206       self.io.write(aplane)\r
207       self.io.write("\n") # end of line\r
208     self.io.write("}\n") # end of chunk\r
209 \r
210   def write_objects(self):\r
211     print "Writing ObjectChunk"\r
212     # scene\r
213     scene=Blender.Scene.GetCurrent()\r
214 \r
215     if self.isJoin:\r
216       base = Blender.Object.New("Mesh", name)\r
217       scene.objects.link(base)\r
218       for obj in self.objs:\r
219         if obj.getType() != 'Mesh':\r
220           continue\r
221         # apply modifiers\r
222         mesh=Blender.Mesh.New()\r
223         mesh.getFromObject(obj.name)\r
224         dumy = Blender.Object.New("Mesh", "dumy")\r
225         dumy.link(mesh)\r
226         # apply matrix\r
227         dumy.setMatrix(obj.matrixWorld)\r
228         scene.objects.link(dumy)\r
229         try:\r
230           base.join([dumy])\r
231         except RuntimeError, e:\r
232           print e\r
233         scene.objects.unlink(dumy)\r
234       self.objs=[base]\r
235 \r
236     # each object\r
237     for obj in self.objs:\r
238       if obj.getType() != 'Mesh':\r
239         continue\r
240       self.write_object(obj)\r
241 \r
242     # join clean up\r
243     if self.isJoin:\r
244       scene.objects.unlink(base)\r
245 \r
246   def write_object(self, obj, depth=0):\r
247       self.io.write("Object \""+obj.name+"\" {\n")\r
248 \r
249       # global matrix\r
250       matrix=obj.matrixWorld\r
251       # rotate to y-up\r
252       matrix*=Blender.Mathutils.RotationMatrix(-90, 4, 'x')\r
253       # scale\r
254       matrix*=Blender.Mathutils.ScaleMatrix(SCALING_FACOR, 4)\r
255 \r
256       # depth\r
257       self.io.write("\tdepth %d\n" % depth)\r
258 \r
259       # mirroring        \r
260       isMirrorring=False\r
261       for mod in obj.modifiers:\r
262           if mod.name=="Mirror":\r
263               isMirrorring=True\r
264               break\r
265       if isMirrorring:\r
266           self.io.write("\tmirror 1\n")\r
267           self.io.write("\tmirror_axis 1\n")\r
268 \r
269       if obj.getType() == 'Mesh':\r
270         mesh=Blender.Mesh.New()\r
271         ############################################################\r
272         # not applied modifiers\r
273         ############################################################\r
274         mesh.getFromObject(obj.name, 1)\r
275 \r
276         # vertices\r
277         self.io.write("\tvertex %d {\n" % len(mesh.verts))\r
278         for vert in mesh.verts:\r
279           x, y, z = apply_transform(vert.co, matrix)\r
280           self.io.write("\t\t%f %f %f\n" % (x, y, z)) # rotate to y-up\r
281         self.io.write("\t}\n")\r
282 \r
283         # faces\r
284         self.io.write("\tface %d {\n" % len(mesh.faces))\r
285         for face in mesh.faces:\r
286           poly_cnt = len(face.v)\r
287           # V\r
288           verts =list(face.v)\r
289           self.io.write("\t\t%d V(" % poly_cnt)\r
290           for i in reversed(range(poly_cnt)): # reverse normal\r
291             self.io.write("%d " % verts[i].index)\r
292           self.io.write(")")\r
293           # mat\r
294           if len(mesh.materials):\r
295             self.io.write(" M(%d)" % self.materials.index(mesh.materials[face.mat].name))\r
296           # UV\r
297           if mesh.faceUV:\r
298             uv = list(face.uv)\r
299             if len(uv)>0:\r
300               self.io.write(" UV(")\r
301               for i in reversed(range(poly_cnt)): # reverse normal\r
302                 self.io.write("%f %f " % (uv[i][0], 1.0-uv[i][1])) # reverse V\r
303               self.io.write(")")\r
304           self.io.write("\n")\r
305         self.io.write("\t}\n") # end of faces\r
306       self.io.write("}\n") # end of object\r
307 \r
308   def write_objects_hierarchical(self, node, depth=0):\r
309     self.write_object(Blender.Object.Get(node.name), depth=depth)\r
310     for child in node.children:\r
311       self.write_objects_hierarchical(child, depth+1)\r
312 \r
313 def export_mqo(fileName):\r
314   fileName=fileName.decode(FS_ENCODING)\r
315   print \r
316   Blender.Window.WaitCursor(1) \r
317   t = Blender.sys.time() \r
318 \r
319   if not fileName.lower().endswith(MQO_EXT): \r
320     fileName += MQO_EXT\r
321   print "export to " + fileName\r
322 \r
323 \r
324   scene=Blender.Scene.GetCurrent()\r
325   if ARG=='all':\r
326     exporter=MqoExporter(fileName)\r
327     exporter.do(scene.objects)\r
328   elif ARG=='selected':\r
329     exporter=MqoExporter(fileName)\r
330     exporter.do(Blender.Object.GetSelected())\r
331   elif ARG=="alljoined":\r
332     exporter=MqoExporter(fileName)\r
333     exporter.do(scene.objects, True)\r
334   elif ARG=="seljoined":\r
335     exporter=MqoExporter(fileName)\r
336     exporter.do(Blender.Object.GetSelected(), True)\r
337   elif ARG=="hierarchy":\r
338     exporter=MqoExporter(fileName)\r
339     # parse scene\r
340     tree=SceneGraph()\r
341     for object in scene.objects:\r
342       tree.addObject(object)\r
343     # active object and descendant\r
344     active = scene.objects.active \r
345     exporter.do_hierarchy(tree.get(active.name))\r
346  \r
347   print 'My Script finished in %.2f seconds' % (Blender.sys.time()-t) \r
348   Blender.Redraw()\r
349   Blender.Window.WaitCursor(0) \r
350  \r
351 def apply_transform(vec, matrix):\r
352   x, y, z = vec\r
353   xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]\r
354   return  x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\\r
355       x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\\r
356       x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc\r
357 \r
358 #--MAIN\r
359 Blender.Window.FileSelector(\r
360     export_mqo, 'Export Metasequoia MQO', Blender.sys.makename(ext=MQO_EXT))\r
361 \r