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.
30 'category': 'Import/Export',
31 'name': 'Export: Metasequioa Model Format (.mqo)',
35 'location': 'File > Export',
36 'description': 'Export to the Metasequioa Model Format (.mqo)',
37 'warning': '', # used for warning icon and text in addons panel
38 'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
45 return sys.version_info[0]<3
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
74 from Blender import Mathutils
81 material=MQOMaterial(m.name, 3)
82 material.r=m.rgbCol[0]
83 material.g=m.rgbCol[1]
84 material.b=m.rgbCol[2]
96 material=MQOMaterial(m.name, 3)
97 material.r=m.diffuse_color[0]
98 material.g=m.diffuse_color[1]
99 material.b=m.diffuse_color[2]
101 material.amb=m.ambient
105 def apply_transform(vec, matrix):
107 xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
108 return x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\
109 x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\
110 x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
112 def convert_to_mqo(vec):
113 return vec.x, vec.z, -vec.y
116 class OutlineNode(object):
117 __slots__=['o', 'children']
118 def __init__(self, o):
123 return "<Node %s>" % self.o
126 class ObjectInfo(object):
127 __slots__=['object', 'depth', 'material_map']
128 def __init__(self, o, depth):
134 return "<ObjectInfo %d %s>" % (self.depth, self.object)
137 class MqoExporter(object):
138 __slots__=["materials", "objects", 'scale', 'apply_modifier',]
139 def __init__(self, scale, apply_modifier):
143 self.apply_modifier=apply_modifier
145 def setup(self, scene):
148 for o in scene.objects:
149 object_node_map[o]=OutlineNode(o)
150 for node in object_node_map.values():
152 object_node_map[node.o.parent].children.append(node)
155 root=object_node_map[scene.objects.active]
158 if root.o.type.upper()=='EMPTY':
160 for node in root.children:
165 def __setup(self, node, depth=0):
166 info=ObjectInfo(node.o, depth)
167 self.objects.append(info)
168 if node.o.type.upper()=='MESH':
170 for i, m in enumerate(node.o.data.materials):
171 info.material_map[i]=self.__getOrAddMaterial(m)
173 for child in node.children:
174 self.__setup(child, depth+1)
176 def __getOrAddMaterial(self, material):
177 for i, m in enumerate(self.materials):
180 index=len(self.materials)
181 self.materials.append(material)
184 def write(self, path):
185 io=bl.Writer(path, 'cp932')
186 self.__write_header(io)
187 self.__write_scene(io)
188 print("Writing MaterialChunk")
189 self.__write_materials(io, os.path.dirname(path))
190 print("Writing ObjectChunk")
191 for info in self.objects:
192 self.__write_object(io, info)
197 def __write_header(self, io):
198 io.write("Metasequoia Document\r\n")
199 io.write("Format Text Ver 1.0\r\n")
202 def __write_scene(self, io):
203 print("Writing SceneChunk")
204 io.write("Scene {\r\n")
207 def __write_materials(self, io, dirname):
209 io.write("Material %d {\r\n" % (len(self.materials)))
210 for m in self.materials:
211 io.write(str(materialToMqo(m)))
212 # ToDo separated alpha texture
213 for filename in bl.material.eachTexturePath(m):
214 if len(dirname)>0 and filename.startswith(dirname):
216 filename=filename[len(dirname)+1:]
217 io.write(" tex(\"%s\")" % filename)
223 def __write_object(self, io, info):
227 if obj.type.upper()=='MESH' or obj.type.upper()=='EMPTY':
233 io.write("Object \""+obj.name+"\" {\r\n")
236 io.write("\tdepth %d\r\n" % info.depth)
239 if not self.apply_modifier:
240 if bl.modifier.hasType(obj, 'MIRROR'):
241 io.write("\tmirror 1\r\n")
242 io.write("\tmirror_axis 1\r\n")
244 if obj.type.upper()=='MESH':
245 # duplicate and applyMatrix
246 copyMesh, copyObj=bl.object.duplicate(obj)
248 copyObj.scale=obj.scale
249 bpy.ops.object.scale_apply()
250 copyObj.rotation_euler=obj.rotation_euler
251 bpy.ops.object.rotation_apply()
252 copyObj.location=obj.location
253 bpy.ops.object.location_apply()
255 if self.apply_modifier:
257 while bl.object.hasShapeKey(copyObj):
258 bpy.ops.object.shape_key_remove()
259 for m in [m for m in copyObj.modifiers]:
260 if m.type=='SOLIDFY':
262 elif m.type=='ARMATURE':
263 bpy.ops.object.modifier_apply(modifier=m.name)
264 elif m.type=='MIRROR':
265 bpy.ops.object.modifier_apply(modifier=m.name)
269 self.__write_mesh(io, copyMesh, info.material_map)
270 bl.object.delete(copyObj)
272 io.write("}\r\n") # end of object
274 def __write_mesh(self, io, mesh, material_map):
276 io.write("\tvertex %d {\r\n" % len(mesh.verts))
277 for vert in mesh.verts:
278 x, y, z = convert_to_mqo(vert.co)
279 io.write("\t\t%f %f %f\r\n" %
280 (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up
284 io.write("\tface %d {\r\n" % len(mesh.faces))
285 for i, face in enumerate(mesh.faces):
286 count=bl.face.getVertexCount(face)
288 io.write("\t\t%d V(" % count)
289 for j in reversed(bl.face.getVertices(face)):
293 if len(mesh.materials):
295 material_map[bl.face.getMaterialIndex(face)])
297 if bl.mesh.hasUV(mesh) and bl.mesh.hasFaceUV(mesh, i, face):
299 for uv in reversed(bl.mesh.getFaceUV(mesh, i, face, count)):
300 # reverse vertical value
301 io.write("%f %f " % (uv[0], 1.0-uv[1]))
304 io.write("\t}\r\n") # end of faces
307 def __execute(filename, scene, scale=10, apply_modifier=False):
308 if not scene.objects.active:
309 bl.message('no active object !')
312 exporter=MqoExporter(scale, apply_modifier)
313 exporter.setup(scene)
314 exporter.write(filename)
319 def execute_24(filename):
320 scene=Blender.Scene.GetCurrent()
321 bl.initialize('mqo_export', scene)
323 filename.decode(bl.INTERNAL_ENCODING),
328 Blender.Window.FileSelector(
330 'Export Metasequoia MQO',
331 Blender.sys.makename(ext='.mqo'))
335 def execute_25(path, scene, scale, apply_modifier):
336 bl.initialize('mqo_export', scene)
337 __execute(path, scene, scale, apply_modifier)
341 class EXPORT_OT_mqo(bpy.types.Operator):
342 '''Save a Metasequoia MQO file.'''
343 bl_idname = "export_scene.mqo"
344 bl_label = 'Export MQO'
346 # List of operator properties, the attributes will be assigned
347 # to the class instance from the operator settings before calling.
348 filepath = bpy.props.StringProperty()
349 filename = bpy.props.StringProperty()
350 directory = bpy.props.StringProperty()
352 scale = bpy.props.FloatProperty(
354 description="Scale the MQO by this value",
355 min=0.0001, max=1000000.0,
356 soft_min=0.001, soft_max=100.0, default=10.0)
358 apply_modifier = bpy.props.BoolProperty(
359 name="ApplyModifier",
360 description="Would apply modifiers",
363 def execute(self, context):
365 self.properties.filepath,
367 self.properties.scale,
368 self.properties.apply_modifier)
371 def invoke(self, context, event):
373 wm.add_fileselect(self)
374 return 'RUNNING_MODAL'
377 def menu_func(self, context):
378 default_path=bpy.data.filepath.replace(".blend", ".mqo")
379 self.layout.operator(
380 EXPORT_OT_mqo.bl_idname,
381 text="Metasequoia (.mqo)",
383 ).filepath=default_path
386 bpy.types.register(EXPORT_OT_mqo)
387 bpy.types.INFO_MT_file_export.append(menu_func)
390 bpy.types.unregister(EXPORT_OT_mqo)
391 bpy.types.INFO_MT_file_export.remove(menu_func)
393 if __name__ == "__main__":