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.
32 'category': 'Import/Export',
33 'name': 'Export: Metasequioa Model Format (.mqo)',
37 'location': 'File > Export',
38 'description': 'Export to the Metasequioa Model Format (.mqo)',
39 'warning': '', # used for warning icon and text in addons panel
40 'wiki_url': 'http://sourceforge.jp/projects/meshio/wiki/FrontPage',
41 'tracker_url': 'http://sourceforge.jp/ticket/newticket.php?group_id=5081',
48 return sys.version_info[0]<3
51 class MQOMaterial(object):
53 'name', 'shader', 'r', 'g', 'b', 'a',
56 def __init__(self, name, shader=3):
68 return "\"%s\" shader(%d) col(%f %f %f %f) dif(%f) amb(%f) emi(%f)" % (
69 self.name, self.shader, self.r, self.g, self.b, self.a,
70 self.dif, self.amb, self.emi
77 from Blender import Mathutils
84 material=MQOMaterial(m.name, 3)
85 material.r=m.rgbCol[0]
86 material.g=m.rgbCol[1]
87 material.b=m.rgbCol[2]
99 material=MQOMaterial(m.name, 3)
100 material.r=m.diffuse_color[0]
101 material.g=m.diffuse_color[1]
102 material.b=m.diffuse_color[2]
104 material.amb=m.ambient
108 def apply_transform(vec, matrix):
110 xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
111 return x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,\
112 x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,\
113 x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
115 def convert_to_mqo(vec):
116 return vec.x, vec.z, -vec.y
119 class OutlineNode(object):
120 __slots__=['o', 'children']
121 def __init__(self, o):
126 return "<Node %s>" % self.o
129 class ObjectInfo(object):
130 __slots__=['object', 'depth', 'material_map']
131 def __init__(self, o, depth):
137 return "<ObjectInfo %d %s>" % (self.depth, self.object)
140 class MqoExporter(object):
141 __slots__=["materials", "objects", 'scale', 'apply_modifier',]
142 def __init__(self, scale, apply_modifier):
146 self.apply_modifier=apply_modifier
148 def setup(self, scene):
151 for o in scene.objects:
152 object_node_map[o]=OutlineNode(o)
153 for node in object_node_map.values():
155 object_node_map[node.o.parent].children.append(node)
158 root=object_node_map[scene.objects.active]
161 if root.o.type.upper()=='EMPTY':
163 for node in root.children:
168 def __setup(self, node, depth=0):
169 info=ObjectInfo(node.o, depth)
170 self.objects.append(info)
171 if node.o.type.upper()=='MESH':
173 for i, m in enumerate(node.o.data.materials):
174 info.material_map[i]=self.__getOrAddMaterial(m)
176 for child in node.children:
177 self.__setup(child, depth+1)
179 def __getOrAddMaterial(self, material):
180 for i, m in enumerate(self.materials):
183 index=len(self.materials)
184 self.materials.append(material)
187 def write(self, path):
188 bl.message("open: "+path)
189 io=bl.Writer(path, 'cp932')
190 self.__write_header(io)
191 self.__write_scene(io)
192 print("Writing MaterialChunk")
193 self.__write_materials(io, os.path.dirname(path))
194 print("Writing ObjectChunk")
195 for info in self.objects:
196 self.__write_object(io, info)
201 def __write_header(self, io):
202 io.write("Metasequoia Document\r\n")
203 io.write("Format Text Ver 1.0\r\n")
206 def __write_scene(self, io):
207 print("Writing SceneChunk")
208 io.write("Scene {\r\n")
211 def __write_materials(self, io, dirname):
213 io.write("Material %d {\r\n" % (len(self.materials)))
214 for m in self.materials:
215 io.write(str(materialToMqo(m)))
216 # ToDo separated alpha texture
217 for filename in bl.material.eachTexturePath(m):
218 if len(dirname)>0 and filename.startswith(dirname):
220 filename=filename[len(dirname)+1:]
221 io.write(" tex(\"%s\")" % filename)
227 def __write_object(self, io, info):
231 if obj.type.upper()=='MESH' or obj.type.upper()=='EMPTY':
237 io.write("Object \""+obj.name+"\" {\r\n")
240 io.write("\tdepth %d\r\n" % info.depth)
243 if not self.apply_modifier:
244 if bl.modifier.hasType(obj, 'MIRROR'):
245 io.write("\tmirror 1\r\n")
246 io.write("\tmirror_axis 1\r\n")
248 if obj.type.upper()=='MESH':
249 # duplicate and applyMatrix
250 copyMesh, copyObj=bl.object.duplicate(obj)
252 copyObj.scale=obj.scale
253 bpy.ops.object.scale_apply()
254 copyObj.rotation_euler=obj.rotation_euler
255 bpy.ops.object.rotation_apply()
256 copyObj.location=obj.location
257 bpy.ops.object.location_apply()
259 if self.apply_modifier:
261 while bl.object.hasShapeKey(copyObj):
262 bpy.ops.object.shape_key_remove()
263 for m in [m for m in copyObj.modifiers]:
264 if m.type=='SOLIDFY':
266 elif m.type=='ARMATURE':
267 bpy.ops.object.modifier_apply(modifier=m.name)
268 elif m.type=='MIRROR':
269 bpy.ops.object.modifier_apply(modifier=m.name)
273 self.__write_mesh(io, copyMesh, info.material_map)
274 bl.object.delete(copyObj)
276 io.write("}\r\n") # end of object
278 def __write_mesh(self, io, mesh, material_map):
280 io.write("\tvertex %d {\r\n" % len(mesh.verts))
281 for vert in mesh.verts:
282 x, y, z = convert_to_mqo(vert.co)
283 io.write("\t\t%f %f %f\r\n" %
284 (x*self.scale, y*self.scale, z*self.scale)) # rotate to y-up
288 io.write("\tface %d {\r\n" % len(mesh.faces))
289 for i, face in enumerate(mesh.faces):
290 count=bl.face.getVertexCount(face)
292 io.write("\t\t%d V(" % count)
293 for j in reversed(bl.face.getVertices(face)):
297 if len(mesh.materials):
299 material_map[bl.face.getMaterialIndex(face)])
301 if bl.mesh.hasUV(mesh) and bl.mesh.hasFaceUV(mesh, i, face):
303 for uv in reversed(bl.mesh.getFaceUV(mesh, i, face, count)):
304 # reverse vertical value
305 io.write("%f %f " % (uv[0], 1.0-uv[1]))
308 io.write("\t}\r\n") # end of faces
311 def __execute(filename, scene, scale=10, apply_modifier=False):
312 if scene.objects.active:
313 exporter=MqoExporter(scale, apply_modifier)
314 exporter.setup(scene)
315 exporter.write(filename)
317 bl.message('no active object !')
322 def execute_24(filename):
323 scene=Blender.Scene.GetCurrent()
324 bl.initialize('mqo_export', scene)
326 filename.decode(bl.INTERNAL_ENCODING),
331 Blender.Window.FileSelector(
333 'Export Metasequoia MQO',
334 Blender.sys.makename(ext='.mqo'))
338 def execute_25(path, scene, scale, apply_modifier):
339 bl.initialize('mqo_export', scene)
340 __execute(path, scene, scale, apply_modifier)
344 class EXPORT_OT_mqo(bpy.types.Operator):
345 '''Save a Metasequoia MQO file.'''
346 bl_idname = "export_scene.mqo"
347 bl_label = 'Export MQO'
349 # List of operator properties, the attributes will be assigned
350 # to the class instance from the operator settings before calling.
351 filepath = bpy.props.StringProperty()
352 filename = bpy.props.StringProperty()
353 directory = bpy.props.StringProperty()
355 scale = bpy.props.FloatProperty(
357 description="Scale the MQO by this value",
358 min=0.0001, max=1000000.0,
359 soft_min=0.001, soft_max=100.0, default=10.0)
361 apply_modifier = bpy.props.BoolProperty(
362 name="ApplyModifier",
363 description="Would apply modifiers",
366 def execute(self, context):
368 self.properties.filepath,
370 self.properties.scale,
371 self.properties.apply_modifier)
374 def invoke(self, context, event):
375 wm=context.window_manager
377 wm.fileselect_add(self)
379 wm.add_fileselect(self)
380 return 'RUNNING_MODAL'
383 def menu_func(self, context):
384 default_path=bpy.data.filepath.replace(".blend", ".mqo")
385 self.layout.operator(
386 EXPORT_OT_mqo.bl_idname,
387 text="Metasequoia (.mqo)",
389 ).filepath=default_path
392 bpy.types.INFO_MT_file_export.append(menu_func)
395 bpy.types.INFO_MT_file_export.remove(menu_func)
397 if __name__ == "__main__":