5 Name: 'Metasequoia (.mqo)...'
8 Tooltip: 'Save as Metasequoia MQO File'
10 __author__= 'ousttrue'
11 __url__ = ["http://gunload.web.fc2.com/blender/"]
14 This script is an exporter to MQO file format.
18 Run this script from "File->Export" menu.
21 0.2 20100518: refactoring.
22 0.3 20100606: integrate 2.4 and 2.5.
23 0.4 20100626: refactoring.
24 0.5 20100710: add [apply_modifier] option(2.5 only).
25 0.6 20100714: remove shape_key when apply_modifier. fix material.
26 2.0 20100724: update for Blender2.53.
27 2.1 20101005: update for Blender2.54.
28 2.2 20101228: update for Blender2.55.
29 2.4 20110429: update for Blender2.57b.
33 'category': 'Import/Export',
34 'name': 'Export: Metasequioa Model Format (.mqo)',
38 'location': 'File > Export',
39 'description': 'Export to the Metasequioa Model Format (.mqo)',
40 'warning': '', # used for warning icon and text in addons panel
41 'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
42 'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
48 class MQOMaterial(object):
50 'name', 'shader', 'r', 'g', 'b', 'a',
53 def __init__(self, name, shader=3):
65 return "\"%s\" shader(%d) col(%f %f %f %f) dif(%f) amb(%f) emi(%f)" % (
66 self.name, self.shader, self.r, self.g, self.b, self.a,
67 self.dif, self.amb, self.emi
75 from . import bl25 as bl
78 material=MQOMaterial(m.name, 3)
79 material.r=m.diffuse_color[0]
80 material.g=m.diffuse_color[1]
81 material.b=m.diffuse_color[2]
83 material.amb=m.ambient
87 def apply_transform(vec, matrix):
89 xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
90 return x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\
91 x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\
92 x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
94 def convert_to_mqo(vec):
95 return vec.x, vec.z, -vec.y
98 class OutlineNode(object):
99 __slots__=['o', 'children']
100 def __init__(self, o):
105 return "<Node %s>" % self.o
108 class ObjectInfo(object):
109 __slots__=['object', 'depth', 'material_map']
110 def __init__(self, o, depth):
116 return "<ObjectInfo %d %s>" % (self.depth, self.object)
119 class MqoExporter(object):
120 __slots__=["materials", "objects", 'scale', 'apply_modifier',]
121 def __init__(self, scale, apply_modifier):
125 self.apply_modifier=apply_modifier
127 def setup(self, scene):
130 for o in scene.objects:
131 object_node_map[o]=OutlineNode(o)
132 for node in object_node_map.values():
134 object_node_map[node.o.parent].children.append(node)
137 root=object_node_map[scene.objects.active]
140 if root.o.type.upper()=='EMPTY':
142 for node in root.children:
147 def __setup(self, node, depth=0):
148 info=ObjectInfo(node.o, depth)
149 self.objects.append(info)
150 if node.o.type.upper()=='MESH':
152 for i, m in enumerate(node.o.data.materials):
153 info.material_map[i]=self.__getOrAddMaterial(m)
155 for child in node.children:
156 self.__setup(child, depth+1)
158 def __getOrAddMaterial(self, material):
159 for i, m in enumerate(self.materials):
162 index=len(self.materials)
163 self.materials.append(material)
166 def write(self, path):
167 bl.message("open: "+path)
168 io=bl.Writer(path, 'cp932')
169 self.__write_header(io)
170 self.__write_scene(io)
171 print("Writing MaterialChunk")
172 self.__write_materials(io, os.path.dirname(path))
173 print("Writing ObjectChunk")
174 for info in self.objects:
175 self.__write_object(io, info)
180 def __write_header(self, io):
181 io.write("Metasequoia Document\r\n")
182 io.write("Format Text Ver 1.0\r\n")
185 def __write_scene(self, io):
186 print("Writing SceneChunk")
187 io.write("Scene {\r\n")
190 def __write_materials(self, io, dirname):
192 io.write("Material %d {\r\n" % (len(self.materials)))
193 for m in self.materials:
194 io.write(str(materialToMqo(m)))
195 # ToDo separated alpha texture
196 for filename in bl.material.eachTexturePath(m):
197 if len(dirname)>0 and filename.startswith(dirname):
199 filename=filename[len(dirname)+1:]
200 io.write(" tex(\"%s\")" % filename)
206 def __write_object(self, io, info):
210 if obj.type.upper()=='MESH' or obj.type.upper()=='EMPTY':
216 io.write("Object \""+obj.name+"\" {\r\n")
219 io.write("\tdepth %d\r\n" % info.depth)
222 if not self.apply_modifier:
223 if bl.modifier.hasType(obj, 'MIRROR'):
224 io.write("\tmirror 1\r\n")
225 io.write("\tmirror_axis 1\r\n")
227 if obj.type.upper()=='MESH':
228 # duplicate and applyMatrix
229 copyMesh, copyObj=bl.object.duplicate(obj)
231 copyObj.scale=obj.scale
232 bpy.ops.object.scale_apply()
233 copyObj.rotation_euler=obj.rotation_euler
234 bpy.ops.object.rotation_apply()
235 copyObj.location=obj.location
236 bpy.ops.object.location_apply()
238 if self.apply_modifier:
240 while bl.object.hasShapeKey(copyObj):
241 bpy.ops.object.shape_key_remove()
242 for m in [m for m in copyObj.modifiers]:
243 if m.type=='SOLIDFY':
245 elif m.type=='ARMATURE':
246 bpy.ops.object.modifier_apply(modifier=m.name)
247 elif m.type=='MIRROR':
248 bpy.ops.object.modifier_apply(modifier=m.name)
252 self.__write_mesh(io, copyMesh, info.material_map)
253 bl.object.delete(copyObj)
255 io.write("}\r\n") # end of object
257 def __write_mesh(self, io, mesh, material_map):
259 io.write("\tvertex %d {\r\n" % len(mesh.vertices))
260 for vert in mesh.vertices:
261 x, y, z = convert_to_mqo(vert.co)
262 io.write("\t\t%f %f %f\r\n" %
263 (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up
267 io.write("\tface %d {\r\n" % len(mesh.faces))
268 for i, face in enumerate(mesh.faces):
269 count=bl.face.getVertexCount(face)
271 io.write("\t\t%d V(" % count)
272 for j in reversed(bl.face.getVertices(face)):
276 if len(mesh.materials):
278 material_map[bl.face.getMaterialIndex(face)])
280 if bl.mesh.hasUV(mesh) and bl.mesh.hasFaceUV(mesh, i, face):
282 for uv in reversed(bl.mesh.getFaceUV(mesh, i, face, count)):
283 # reverse vertical value
284 io.write("%f %f " % (uv[0], 1.0-uv[1]))
287 io.write("\t}\r\n") # end of faces
290 def _execute(filepath='', scale=10, apply_modifier=False):
291 if bl.object.getActive():
292 exporter=MqoExporter(scale, apply_modifier)
293 exporter.setup(bl.scene.get())
294 exporter.write(filepath)
296 bl.message('no active object !')