4 Name: 'Metasequoia (.mqo)...'
\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
14 __author__= 'ousttrue'
\r
15 __url__ = ["http://gunload.web.fc2.com/blender/"]
\r
16 __version__= '1.0 2008/01/28'
\r
18 This script is an exporter to MQO file format.
\r
22 Run this script from "File->Export" menu.
\r
25 # LICENSE (BSD Style)
\r
27 # Redistribution and use in source and binary forms, with or without
\r
28 # modification, are permitted provided that the following conditions
\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
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
54 # rewrite. implement object hierarchy
\r
63 ARG = __script__['arg'] # user selected argument
\r
70 SCALING_FACOR=100 # scaling factor
\r
74 __slots__=['name', 'children']
\r
75 def __init__(self, name="__scene__"):
\r
79 def addChild(self, child):
\r
80 self.children.append(child)
\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
87 class NodeIterator(object):
\r
88 __slots__=["list", "index"]
\r
89 def __init__(self, node):
\r
94 def setup(self, node):
\r
95 self.list.append(node)
\r
96 for child in node.children:
\r
103 if self.index<len(self.list):
\r
104 node=self.list[self.index]
\r
108 raise StopIteration
\r
110 class SceneGraph(object):
\r
111 __slots__=["root", "dict"]
\r
112 def __init__(self):
\r
116 def addObject(self, object):
\r
118 if object.name in self.dict:
\r
121 parent=object.getParent()
\r
122 node=Node(object.name)
\r
124 if not parent.name in self.dict:
\r
125 addNode(self.dict, parent)
\r
126 self.dict[parent.name].addChild(node)
\r
128 self.root.addChild(node)
\r
129 self.dict[object.name]=node
\r
131 def get(self, name):
\r
132 if name in self.dict:
\r
133 return self.dict[name]
\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
142 def do(self, objs, isJoin=False):
\r
145 self.io=open(self.filename, "w")
\r
146 self.write_header()
\r
147 self.write_materials()
\r
148 self.write_objects()
\r
152 def do_hierarchy(self, node):
\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
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
167 def write_materials(self):
\r
168 print "Writing MaterialChunk"
\r
169 dirname=os.path.dirname(self.filename)
\r
173 for obj in self.objs:
\r
174 if obj.getType() != 'Mesh':
\r
176 for mat in obj.getData(mesh=1).materials:
\r
178 materials.add(mat.name)
\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
188 for mtex in m.getTextures():
\r
189 if mtex and mtex.tex and mtex.tex.getImage():
\r
190 image=mtex.tex.getImage()
\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
198 tex=" tex(\"%s\")" % imagePath
\r
200 aplane=" aplane(\"%s\")" % imagePath
\r
202 self.io.write("\"%s\" shader(3) col(1 1 1 1)" % material_name)
\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
206 self.io.write(aplane)
\r
207 self.io.write("\n") # end of line
\r
208 self.io.write("}\n") # end of chunk
\r
210 def write_objects(self):
\r
211 print "Writing ObjectChunk"
\r
213 scene=Blender.Scene.GetCurrent()
\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
222 mesh=Blender.Mesh.New()
\r
223 mesh.getFromObject(obj.name)
\r
224 dumy = Blender.Object.New("Mesh", "dumy")
\r
227 dumy.setMatrix(obj.matrixWorld)
\r
228 scene.objects.link(dumy)
\r
231 except RuntimeError, e:
\r
233 scene.objects.unlink(dumy)
\r
237 for obj in self.objs:
\r
238 if obj.getType() != 'Mesh':
\r
240 self.write_object(obj)
\r
244 scene.objects.unlink(base)
\r
246 def write_object(self, obj, depth=0):
\r
247 self.io.write("Object \""+obj.name+"\" {\n")
\r
250 matrix=obj.matrixWorld
\r
252 matrix*=Blender.Mathutils.RotationMatrix(-90, 4, 'x')
\r
254 matrix*=Blender.Mathutils.ScaleMatrix(SCALING_FACOR, 4)
\r
257 self.io.write("\tdepth %d\n" % depth)
\r
261 for mod in obj.modifiers:
\r
262 if mod.name=="Mirror":
\r
266 self.io.write("\tmirror 1\n")
\r
267 self.io.write("\tmirror_axis 1\n")
\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
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
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
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
294 if len(mesh.materials):
\r
295 self.io.write(" M(%d)" % self.materials.index(mesh.materials[face.mat].name))
\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
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
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
313 def export_mqo(fileName):
\r
314 fileName=fileName.decode(FS_ENCODING)
\r
316 Blender.Window.WaitCursor(1)
\r
317 t = Blender.sys.time()
\r
319 if not fileName.lower().endswith(MQO_EXT):
\r
320 fileName += MQO_EXT
\r
321 print "export to " + fileName
\r
324 scene=Blender.Scene.GetCurrent()
\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
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
347 print 'My Script finished in %.2f seconds' % (Blender.sys.time()-t)
\r
349 Blender.Window.WaitCursor(0)
\r
351 def apply_transform(vec, matrix):
\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
359 Blender.Window.FileSelector(
\r
360 export_mqo, 'Export Metasequoia MQO', Blender.sys.makename(ext=MQO_EXT))
\r