[REMOVE] blender export-import of emf file (move in ege)
This commit is contained in:
parent
c750b5fd53
commit
c4379885b3
@ -1,218 +0,0 @@
|
|||||||
# add this folder in ~/.config/blender/2.66/scripts/addons
|
|
||||||
|
|
||||||
|
|
||||||
bl_info = {
|
|
||||||
"name": "Ewol Mesh file format emf",
|
|
||||||
"author": "Edouard DUPIN",
|
|
||||||
"blender": (2, 53, 0),
|
|
||||||
"location": "File > Import-Export",
|
|
||||||
"description": "Import-Export emf, Import EMF mesh, UV's, materials and textures",
|
|
||||||
"warning": "",
|
|
||||||
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/EwolMechFile_EMF",
|
|
||||||
"tracker_url": "",
|
|
||||||
"support": 'OFFICIAL',
|
|
||||||
"category": "Import-Export"}
|
|
||||||
|
|
||||||
if "bpy" in locals():
|
|
||||||
import imp
|
|
||||||
if "import_emf" in locals():
|
|
||||||
imp.reload(import_emf)
|
|
||||||
if "export_emf" in locals():
|
|
||||||
imp.reload(export_emf)
|
|
||||||
|
|
||||||
|
|
||||||
import bpy
|
|
||||||
from bpy.props import (BoolProperty,
|
|
||||||
FloatProperty,
|
|
||||||
StringProperty,
|
|
||||||
EnumProperty,
|
|
||||||
)
|
|
||||||
from bpy_extras.io_utils import (ExportHelper,
|
|
||||||
ImportHelper,
|
|
||||||
path_reference_mode,
|
|
||||||
axis_conversion,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ImportEMF(bpy.types.Operator, ImportHelper):
|
|
||||||
"""Load a Wavefront EMF File"""
|
|
||||||
bl_idname = "import_scene.emf"
|
|
||||||
bl_label = "Import EMF"
|
|
||||||
bl_options = {'PRESET', 'UNDO'}
|
|
||||||
|
|
||||||
filename_ext = ".emf"
|
|
||||||
filter_glob = StringProperty(
|
|
||||||
default="*.emf",
|
|
||||||
options={'HIDDEN'},
|
|
||||||
)
|
|
||||||
|
|
||||||
axis_forward = EnumProperty(
|
|
||||||
name="Forward",
|
|
||||||
items=(('X', "X Forward", ""),
|
|
||||||
('Y', "Y Forward", ""),
|
|
||||||
('Z', "Z Forward", ""),
|
|
||||||
('-X', "-X Forward", ""),
|
|
||||||
('-Y', "-Y Forward", ""),
|
|
||||||
('-Z', "-Z Forward", ""),
|
|
||||||
),
|
|
||||||
default='-X',
|
|
||||||
)
|
|
||||||
|
|
||||||
axis_up = EnumProperty(
|
|
||||||
name="Up",
|
|
||||||
items=(('X', "X Up", ""),
|
|
||||||
('Y', "Y Up", ""),
|
|
||||||
('Z', "Z Up", ""),
|
|
||||||
('-X', "-X Up", ""),
|
|
||||||
('-Y', "-Y Up", ""),
|
|
||||||
('-Z', "-Z Up", ""),
|
|
||||||
),
|
|
||||||
default='Z',
|
|
||||||
)
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
# print("Selected: " + context.active_object.name)
|
|
||||||
from . import import_obj
|
|
||||||
|
|
||||||
keywords = self.as_keywords(ignore=("axis_forward",
|
|
||||||
"axis_up",
|
|
||||||
"filter_glob",
|
|
||||||
"split_mode",
|
|
||||||
))
|
|
||||||
|
|
||||||
global_matrix = axis_conversion(from_forward=self.axis_forward,
|
|
||||||
from_up=self.axis_up,
|
|
||||||
).to_4x4()
|
|
||||||
keywords["global_matrix"] = global_matrix
|
|
||||||
|
|
||||||
return import_obj.load(self, context, **keywords)
|
|
||||||
|
|
||||||
def draw(self, context):
|
|
||||||
layout = self.layout
|
|
||||||
|
|
||||||
row = layout.row(align=True)
|
|
||||||
|
|
||||||
row = layout.split(percentage=0.67)
|
|
||||||
row.prop(self, "global_clamp_size")
|
|
||||||
layout.prop(self, "axis_forward")
|
|
||||||
layout.prop(self, "axis_up")
|
|
||||||
|
|
||||||
layout.prop(self, "use_image_search")
|
|
||||||
|
|
||||||
|
|
||||||
class ExportEMF(bpy.types.Operator, ExportHelper):
|
|
||||||
"""Save a Wavefront EMF File"""
|
|
||||||
|
|
||||||
bl_idname = "export_scene.emf"
|
|
||||||
bl_label = 'Export EMF'
|
|
||||||
bl_options = {'PRESET'}
|
|
||||||
|
|
||||||
filename_ext = ".emf"
|
|
||||||
filter_glob = StringProperty(
|
|
||||||
default="*.emf",
|
|
||||||
options={'HIDDEN'},
|
|
||||||
)
|
|
||||||
|
|
||||||
# context group
|
|
||||||
use_selection = BoolProperty(
|
|
||||||
name="Selection Only",
|
|
||||||
description="Export selected objects only",
|
|
||||||
default=True,
|
|
||||||
)
|
|
||||||
# generate binary file
|
|
||||||
use_binary = BoolProperty(
|
|
||||||
name="Binary",
|
|
||||||
description="Export the filein binary mode",
|
|
||||||
default=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
global_scale = FloatProperty(
|
|
||||||
name="Scale",
|
|
||||||
description="Scale all data",
|
|
||||||
min=0.01, max=1000.0,
|
|
||||||
soft_min=0.01,
|
|
||||||
soft_max=1000.0,
|
|
||||||
default=1.0,
|
|
||||||
)
|
|
||||||
|
|
||||||
collision_object_name = StringProperty(
|
|
||||||
name="Collision root name (strat with)",
|
|
||||||
description="The top-level name that will contain the physics shapes",
|
|
||||||
default="phys"
|
|
||||||
)
|
|
||||||
|
|
||||||
axis_forward = EnumProperty(
|
|
||||||
name="Forward",
|
|
||||||
items=(('X', "X Forward", ""),
|
|
||||||
('Y', "Y Forward", ""),
|
|
||||||
('Z', "Z Forward", ""),
|
|
||||||
('-X', "-X Forward", ""),
|
|
||||||
('-Y', "-Y Forward", ""),
|
|
||||||
('-Z', "-Z Forward", ""),
|
|
||||||
),
|
|
||||||
default='-Z',
|
|
||||||
)
|
|
||||||
|
|
||||||
axis_up = EnumProperty(
|
|
||||||
name="Up",
|
|
||||||
items=(('X', "X Up", ""),
|
|
||||||
('Y', "Y Up", ""),
|
|
||||||
('Z', "Z Up", ""),
|
|
||||||
('-X', "-X Up", ""),
|
|
||||||
('-Y', "-Y Up", ""),
|
|
||||||
('-Z', "-Z Up", ""),
|
|
||||||
),
|
|
||||||
default='Y',
|
|
||||||
)
|
|
||||||
|
|
||||||
path_mode = path_reference_mode
|
|
||||||
|
|
||||||
check_extension = True
|
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
from . import export_emf
|
|
||||||
|
|
||||||
from mathutils import Matrix
|
|
||||||
keywords = self.as_keywords(ignore=("axis_forward",
|
|
||||||
"axis_up",
|
|
||||||
"global_scale",
|
|
||||||
"check_existing",
|
|
||||||
"filter_glob",
|
|
||||||
))
|
|
||||||
|
|
||||||
global_matrix = Matrix()
|
|
||||||
|
|
||||||
global_matrix[0][0] = \
|
|
||||||
global_matrix[1][1] = \
|
|
||||||
global_matrix[2][2] = self.global_scale
|
|
||||||
|
|
||||||
global_matrix = (global_matrix *
|
|
||||||
axis_conversion(to_forward=self.axis_forward,
|
|
||||||
to_up=self.axis_up,
|
|
||||||
).to_4x4())
|
|
||||||
|
|
||||||
keywords["global_matrix"] = global_matrix
|
|
||||||
return export_emf.save(self, context, **keywords)
|
|
||||||
|
|
||||||
|
|
||||||
def menu_func_import(self, context):
|
|
||||||
self.layout.operator(ImportEMF.bl_idname, text="Ewol mesh file (.emf)")
|
|
||||||
|
|
||||||
|
|
||||||
def menu_func_export(self, context):
|
|
||||||
self.layout.operator(ExportEMF.bl_idname, text="Ewol mesh File (.emf)")
|
|
||||||
|
|
||||||
|
|
||||||
def register():
|
|
||||||
bpy.utils.register_module(__name__)
|
|
||||||
bpy.types.INFO_MT_file_import.append(menu_func_import)
|
|
||||||
bpy.types.INFO_MT_file_export.append(menu_func_export)
|
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
|
||||||
bpy.utils.unregister_module(__name__)
|
|
||||||
bpy.types.INFO_MT_file_import.remove(menu_func_import)
|
|
||||||
bpy.types.INFO_MT_file_export.remove(menu_func_export)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
register()
|
|
@ -1,661 +0,0 @@
|
|||||||
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
|
|
||||||
import bpy
|
|
||||||
import mathutils
|
|
||||||
import bpy_extras.io_utils
|
|
||||||
|
|
||||||
def getChildren(obj):
|
|
||||||
children = []
|
|
||||||
for ob in bpy.data.objects:
|
|
||||||
if ob.parent == obj:
|
|
||||||
children.append(ob)
|
|
||||||
return children
|
|
||||||
|
|
||||||
|
|
||||||
import bpy
|
|
||||||
from bpy.props import *
|
|
||||||
import mathutils, math, struct
|
|
||||||
from mathutils import *
|
|
||||||
import os
|
|
||||||
from os import remove
|
|
||||||
import time
|
|
||||||
import bpy_extras
|
|
||||||
from bpy_extras.io_utils import ExportHelper
|
|
||||||
import time
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
"""
|
|
||||||
Usage Notes:
|
|
||||||
To create a compound physics collision shape for a mesh in blender:
|
|
||||||
|
|
||||||
1. place the 3D cursor at the origin of the mesh object.
|
|
||||||
2. Add > Empty, name it "physics"
|
|
||||||
3. Create a physics shape with Add > Mesh > Cube, UV Sphere, Cylinder, Cone or create an arbitrary mesh for a ConvexHull shape.
|
|
||||||
4. Parent the new shape to the "physics" Empty.
|
|
||||||
5. The mesh name must start with: Box, Sphere, Cylinder, Cone, Capsule, or ConvexHull, depending on the shape you want.
|
|
||||||
6. Position and scale the shape object, but do not modify the internal vertices, unless it is a ConvexHull type.
|
|
||||||
7. Repeat step 3-6 until your shape is complete. Shapes can only be a 1-level deep hierarchy.
|
|
||||||
8. IMPORTANT: Select the empty object you named "physics"
|
|
||||||
9. Click File > Export > Physics Shapes (.yaml)
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
use_y_up = BoolProperty(name="Convert To Y-Up",
|
|
||||||
description="Converts the values to a Y-Axis Up coordinate system",
|
|
||||||
default=True)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Methods for writing point, scale, and quaternion types to a YAML file.
|
|
||||||
# This particular implementation converts values to a Y-up coordinate system.
|
|
||||||
def out_point3_y_up( v ):
|
|
||||||
return "%g %g %g" % ( v.x, v.z, -v.y )
|
|
||||||
def out_scale3_y_up( s ):
|
|
||||||
return "%g %g %g" % ( s.x, s.z, s.y )
|
|
||||||
def out_quaternion_y_up( q ):
|
|
||||||
return "%g %g %g %g" % ( q.w, q.x, q.z, -q.y )
|
|
||||||
# This implementation maintains blender's Z-up coordinate system.
|
|
||||||
def out_point3_z_up( v ):
|
|
||||||
return "%g %g %g" % ( v.x, v.y, v.z )
|
|
||||||
def out_scale3_z_up( s ):
|
|
||||||
return "%g %g %g" % ( s.x, s.y, s.z )
|
|
||||||
def out_quaternion_z_up( q ):
|
|
||||||
return "%g %g %g %g" % ( q.w, q.x, q.y, q.z )
|
|
||||||
|
|
||||||
|
|
||||||
def getPhysicsShape(obj, mainObjScale, use_y_up=False):
|
|
||||||
shape = ""
|
|
||||||
props = { }
|
|
||||||
name = obj.name.lower()
|
|
||||||
scale = Vector(( abs(obj.scale.x), abs(obj.scale.y), abs(obj.scale.z) ))
|
|
||||||
|
|
||||||
if use_y_up:
|
|
||||||
out_point3 = out_point3_y_up
|
|
||||||
out_scale3 = out_scale3_y_up
|
|
||||||
out_quaternion = out_quaternion_y_up
|
|
||||||
else:
|
|
||||||
out_point3 = out_point3_z_up
|
|
||||||
out_scale3 = out_scale3_z_up
|
|
||||||
out_quaternion = out_quaternion_z_up
|
|
||||||
|
|
||||||
# BOX
|
|
||||||
if name.startswith('box') \
|
|
||||||
or name.startswith('cube'):
|
|
||||||
shape = "Box"
|
|
||||||
props["half-extents"] = out_scale3( scale )
|
|
||||||
# SPHERE
|
|
||||||
elif name.startswith('sph'):
|
|
||||||
shape = "Sphere"
|
|
||||||
props["radius"] = obj.scale.x * mainObjScale.x
|
|
||||||
# CONE
|
|
||||||
elif name.startswith('cone'):
|
|
||||||
shape = "Cone"
|
|
||||||
props["radius"] = obj.scale.x
|
|
||||||
props["height"] = obj.scale.z * 2.0
|
|
||||||
# CYLINDER
|
|
||||||
elif name.startswith('cyl'):
|
|
||||||
shape = "Cylinder"
|
|
||||||
props["half-extents"] = out_scale3( scale )
|
|
||||||
# CAPSULE
|
|
||||||
elif name.startswith('cap'):
|
|
||||||
shape = "Capsule"
|
|
||||||
props["radius"] = obj.scale.x
|
|
||||||
props["height"] = obj.scale.z
|
|
||||||
# CONVEX-HULL
|
|
||||||
elif name.startswith('convex'):
|
|
||||||
shape = "ConvexHull"
|
|
||||||
mesh = obj.to_mesh( bpy.context.scene, True, 'PREVIEW' )
|
|
||||||
props["points"] = ""
|
|
||||||
for v in mesh.vertices:
|
|
||||||
props["points"] += "" + out_point3( v.co ) + "|"
|
|
||||||
props["points"] = props["points"].rstrip("|")
|
|
||||||
if scale != Vector((1,1,1)):
|
|
||||||
props["scale"] = out_scale3( scale )
|
|
||||||
# remove mesh
|
|
||||||
|
|
||||||
print(" shape type : '%s' from element name : '%s'" % (shape, obj.name))
|
|
||||||
|
|
||||||
if obj.location != Vector((0,0,0)):
|
|
||||||
props["origin"] = out_point3( obj.location )
|
|
||||||
|
|
||||||
if obj.rotation_mode == 'QUATERNION':
|
|
||||||
qrot = obj.rotation_quaternion
|
|
||||||
else:
|
|
||||||
qrot = obj.matrix_local.to_quaternion()
|
|
||||||
|
|
||||||
if qrot != Quaternion((1,0,0,0)):
|
|
||||||
props["rotate"] = out_quaternion( qrot )
|
|
||||||
|
|
||||||
return (shape, props)
|
|
||||||
|
|
||||||
|
|
||||||
def writeCollisionShape(object, file, mainObjScale):
|
|
||||||
if len(getChildren(object))==0:
|
|
||||||
# no phisical shape ...
|
|
||||||
return
|
|
||||||
fw = file.write
|
|
||||||
fw('\t\tPhysics : \n')
|
|
||||||
for subObj in getChildren(object):
|
|
||||||
print(" element='%s' type '%s'" % (subObj.name,str(subObj.type)))
|
|
||||||
if subObj.type != 'MESH':
|
|
||||||
continue
|
|
||||||
(shape, props) = getPhysicsShape(subObj, mainObjScale)
|
|
||||||
if shape=="":
|
|
||||||
print("error of shape detection type ...");
|
|
||||||
continue
|
|
||||||
fw("\t\t\t" + shape + "\n" )
|
|
||||||
for (k,v) in props.items():
|
|
||||||
fw("\t\t\t\t%s : %s\n" % (k, v) )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def name_compat(name):
|
|
||||||
if name is None:
|
|
||||||
return 'None'
|
|
||||||
else:
|
|
||||||
return name.replace(' ', '_')
|
|
||||||
|
|
||||||
|
|
||||||
def mesh_triangulate(me):
|
|
||||||
import bmesh
|
|
||||||
bm = bmesh.new()
|
|
||||||
bm.from_mesh(me)
|
|
||||||
bmesh.ops.triangulate(bm, faces=bm.faces)#, use_beauty=False)
|
|
||||||
bm.to_mesh(me)
|
|
||||||
bm.free()
|
|
||||||
|
|
||||||
|
|
||||||
def write_mtl(scene, file, filepath, path_mode, copy_set, mtl_dict):
|
|
||||||
from mathutils import Color
|
|
||||||
world = scene.world
|
|
||||||
if world:
|
|
||||||
world_amb = world.ambient_color
|
|
||||||
else:
|
|
||||||
world_amb = Color((0.0, 0.0, 0.0))
|
|
||||||
source_dir = os.path.dirname(bpy.data.filepath)
|
|
||||||
dest_dir = os.path.dirname(filepath)
|
|
||||||
fw = file.write
|
|
||||||
fw('\nMaterials : %i\n' % len(mtl_dict))
|
|
||||||
mtl_dict_values = list(mtl_dict.values())
|
|
||||||
mtl_dict_values.sort(key=lambda m: m[0])
|
|
||||||
# Write material/image combinations we have used.
|
|
||||||
# Using mtl_dict.values() directly gives un-predictable order.
|
|
||||||
for mtl_mat_name, mat, face_img in mtl_dict_values:
|
|
||||||
# Get the Blender data for the material and the image.
|
|
||||||
# Having an image named None will make a bug, dont do it :)
|
|
||||||
fw('\t%s\n' % mtl_mat_name) # Define a new material: matname_imgname
|
|
||||||
if mat:
|
|
||||||
# convert from blenders spec to 0 - 1000 range.
|
|
||||||
if mat.specular_shader == 'WARDISO':
|
|
||||||
tspec = (0.4 - mat.specular_slope) / 0.0004
|
|
||||||
else:
|
|
||||||
tspec = (mat.specular_hardness - 1) * 1.9607843137254901
|
|
||||||
fw('\t\tNs %.6f\n' % tspec)
|
|
||||||
del tspec
|
|
||||||
fw('\t\tKa %.6f %.6f %.6f\n' % (mat.ambient * world_amb)[:]) # Ambient, uses mirror color,
|
|
||||||
fw('\t\tKd %.6f %.6f %.6f\n' % (mat.diffuse_intensity * mat.diffuse_color)[:]) # Diffuse
|
|
||||||
fw('\t\tKs %.6f %.6f %.6f\n' % (mat.specular_intensity * mat.specular_color)[:]) # Specular
|
|
||||||
if hasattr(mat, "ior"):
|
|
||||||
fw('\t\tNi %.6f\n' % mat.ior) # Refraction index
|
|
||||||
else:
|
|
||||||
fw('\t\tNi %.6f\n' % 1.0)
|
|
||||||
fw('\t\td %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve)
|
|
||||||
# 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
|
|
||||||
if mat.use_shadeless:
|
|
||||||
fw('\t\tillum 0\n') # ignore lighting
|
|
||||||
elif mat.specular_intensity == 0:
|
|
||||||
fw('\t\tillum 1\n') # no specular.
|
|
||||||
else:
|
|
||||||
fw('\t\tillum 2\n') # light normaly
|
|
||||||
else:
|
|
||||||
#write a dummy material here?
|
|
||||||
fw('\t\tNs 0\n')
|
|
||||||
fw('\t\tKa %.6f %.6f %.6f\n' % world_amb[:]) # Ambient, uses mirror color,
|
|
||||||
fw('\t\tKd 0.8 0.8 0.8\n')
|
|
||||||
fw('\t\tKs 0.8 0.8 0.8\n')
|
|
||||||
fw('\t\td 1\n') # No alpha
|
|
||||||
fw('\t\tillum 2\n') # light normaly
|
|
||||||
# Write images!
|
|
||||||
if face_img: # We have an image on the face!
|
|
||||||
filepath = face_img.filepath
|
|
||||||
if filepath: # may be '' for generated images
|
|
||||||
# write relative image path
|
|
||||||
filepath = bpy_extras.io_utils.path_reference(filepath,
|
|
||||||
source_dir,
|
|
||||||
dest_dir,
|
|
||||||
path_mode,
|
|
||||||
"",
|
|
||||||
copy_set,
|
|
||||||
face_img.library)
|
|
||||||
fw('\t\tmap_Kd %s\n' % filepath) # Diffuse mapping image
|
|
||||||
del filepath
|
|
||||||
else:
|
|
||||||
# so we write the materials image.
|
|
||||||
face_img = None
|
|
||||||
if mat: # No face image. if we havea material search for MTex image.
|
|
||||||
image_map = {}
|
|
||||||
# backwards so topmost are highest priority
|
|
||||||
for mtex in reversed(mat.texture_slots):
|
|
||||||
if mtex and mtex.texture and mtex.texture.type == 'IMAGE':
|
|
||||||
image = mtex.texture.image
|
|
||||||
if image:
|
|
||||||
# texface overrides others
|
|
||||||
if( mtex.use_map_color_diffuse
|
|
||||||
and (face_img is None)
|
|
||||||
and (mtex.use_map_warp is False)
|
|
||||||
and (mtex.texture_coords != 'REFLECTION')
|
|
||||||
):
|
|
||||||
image_map["map_Kd"] = image
|
|
||||||
if mtex.use_map_ambient:
|
|
||||||
image_map["map_Ka"] = image
|
|
||||||
# this is the Spec intensity channel but Ks stands for specular Color
|
|
||||||
if mtex.use_map_color_spec: # specular color
|
|
||||||
image_map["map_Ks"] = image
|
|
||||||
if mtex.use_map_hardness: # specular hardness/glossiness
|
|
||||||
image_map["map_Ns"] = image
|
|
||||||
if mtex.use_map_alpha:
|
|
||||||
image_map["map_d"] = image
|
|
||||||
if mtex.use_map_translucency:
|
|
||||||
image_map["map_Tr"] = image
|
|
||||||
if mtex.use_map_normal and (mtex.texture.use_normal_map is True):
|
|
||||||
image_map["map_Bump"] = image
|
|
||||||
if mtex.use_map_normal and (mtex.texture.use_normal_map is False):
|
|
||||||
image_map["map_Disp"] = image
|
|
||||||
if mtex.use_map_color_diffuse and (mtex.texture_coords == 'REFLECTION'):
|
|
||||||
image_map["map_refl"] = image
|
|
||||||
if mtex.use_map_emit:
|
|
||||||
image_map["map_Ke"] = image
|
|
||||||
for key, image in image_map.items():
|
|
||||||
filepath = bpy_extras.io_utils.path_reference(image.filepath,
|
|
||||||
source_dir,
|
|
||||||
dest_dir,
|
|
||||||
path_mode,
|
|
||||||
"",
|
|
||||||
copy_set,
|
|
||||||
image.library)
|
|
||||||
fw('\t\t%s %s\n' % (key, repr(filepath)[1:-1]))
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
" @brief Basic write function. The context and options must be already set.
|
|
||||||
"""
|
|
||||||
def write_file(filepath,
|
|
||||||
objects,
|
|
||||||
scene,
|
|
||||||
EXPORT_GLOBAL_MATRIX=None,
|
|
||||||
EXPORT_PATH_MODE='AUTO',
|
|
||||||
EXPORT_BINARY_MODE=False,
|
|
||||||
EXPORT_COLLISION_NAME=""
|
|
||||||
):
|
|
||||||
if EXPORT_GLOBAL_MATRIX is None:
|
|
||||||
EXPORT_GLOBAL_MATRIX = mathutils.Matrix()
|
|
||||||
|
|
||||||
def veckey3d(v):
|
|
||||||
return round(v.x, 6), round(v.y, 6), round(v.z, 6)
|
|
||||||
|
|
||||||
def veckey2d(v):
|
|
||||||
return round(v[0], 6), round(v[1], 6)
|
|
||||||
|
|
||||||
print('EMF Export path: %r' % filepath)
|
|
||||||
|
|
||||||
time1 = time.time()
|
|
||||||
|
|
||||||
mtlfilepath = os.path.splitext(filepath)[0] + ".mtl"
|
|
||||||
|
|
||||||
file = open(filepath, "w", encoding="utf8", newline="\n")
|
|
||||||
fw = file.write
|
|
||||||
|
|
||||||
# Write Header
|
|
||||||
fw('EMF(STRING)\n') # if binary : fw('EMF(BINARY)\n')
|
|
||||||
fw('# Blender v%s EMF File: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath)))
|
|
||||||
|
|
||||||
# Initialize totals, these are updated each object
|
|
||||||
totverts = totuvco = totno = 1
|
|
||||||
|
|
||||||
face_vert_index = 1
|
|
||||||
|
|
||||||
globalNormals = {}
|
|
||||||
|
|
||||||
# A Dict of Materials
|
|
||||||
# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
|
|
||||||
mtl_dict = {}
|
|
||||||
# Used to reduce the usage of matname_texname materials, which can become annoying in case of
|
|
||||||
# repeated exports/imports, yet keeping unique mat names per keys!
|
|
||||||
# mtl_name: (material.name, image.name)
|
|
||||||
mtl_rev_dict = {}
|
|
||||||
|
|
||||||
copy_set = set()
|
|
||||||
|
|
||||||
# Get all meshes
|
|
||||||
for ob_main in objects:
|
|
||||||
print("**************** '%s' *******************" % str(ob_main.name))
|
|
||||||
if ob_main.type != 'MESH':
|
|
||||||
print(ob_main.name, 'is not a mesh type - ignoring')
|
|
||||||
fw('# can not export : "%s" : type="%s"\n' % (ob_main.name, str(ob_main.type)))
|
|
||||||
continue
|
|
||||||
#print("name : '%s'" % ob_main.name)
|
|
||||||
#for plop in ob_main.child:
|
|
||||||
# print(" child : '%s'" % plop.name)
|
|
||||||
# ignore dupli children
|
|
||||||
if ob_main.parent and ob_main.parent.dupli_type in {'VERTS', 'FACES'}:
|
|
||||||
# XXX
|
|
||||||
print(ob_main.name, 'is a dupli child - ignoring')
|
|
||||||
continue
|
|
||||||
obs = []
|
|
||||||
if ob_main.dupli_type != 'NONE':
|
|
||||||
# XXX
|
|
||||||
print('creating dupli_list on', ob_main.name)
|
|
||||||
ob_main.dupli_list_create(scene)
|
|
||||||
obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list]
|
|
||||||
# XXX debug print
|
|
||||||
print(ob_main.name, 'has', len(obs), 'dupli children')
|
|
||||||
else:
|
|
||||||
obs = [(ob_main, ob_main.matrix_world)]
|
|
||||||
idMesh=0
|
|
||||||
for ob, ob_mat in obs:
|
|
||||||
try:
|
|
||||||
# apply the mesh modifieur at the curent object :
|
|
||||||
me = ob.to_mesh(scene, True, 'PREVIEW', calc_tessface=False)
|
|
||||||
except RuntimeError:
|
|
||||||
me = None
|
|
||||||
if me is None:
|
|
||||||
continue
|
|
||||||
idMesh = idMesh+1;
|
|
||||||
fw('Mesh : %d\n' % idMesh)
|
|
||||||
me.transform(EXPORT_GLOBAL_MATRIX * ob_mat)
|
|
||||||
#print("ploppp : " + str(EXPORT_GLOBAL_MATRIX) )
|
|
||||||
#print("ploppp : " + str(ob_mat) )
|
|
||||||
# _must_ do this first since it re-allocs arrays
|
|
||||||
# triangulate all the mesh :
|
|
||||||
mesh_triangulate(me)
|
|
||||||
# calculated normals:
|
|
||||||
me.calc_normals()
|
|
||||||
# export UV mapping :
|
|
||||||
faceuv = len(me.uv_textures) > 0
|
|
||||||
if faceuv:
|
|
||||||
uv_texture = me.uv_textures.active.data[:]
|
|
||||||
uv_layer = me.uv_layers.active.data[:]
|
|
||||||
me_verts = me.vertices[:]
|
|
||||||
# Make our own list so it can be sorted to reduce context switching
|
|
||||||
face_index_pairs = [(face, index) for index, face in enumerate(me.polygons)]
|
|
||||||
# faces = [ f for f in me.tessfaces ]
|
|
||||||
edges = me.edges
|
|
||||||
if not (len(face_index_pairs) + len(edges) + len(me.vertices)): # Make sure there is somthing to write
|
|
||||||
# clean up
|
|
||||||
bpy.data.meshes.remove(me)
|
|
||||||
continue # dont bother with this mesh.
|
|
||||||
|
|
||||||
materials = me.materials[:]
|
|
||||||
material_names = [m.name if m else None for m in materials]
|
|
||||||
# avoid bad index errors
|
|
||||||
if not materials:
|
|
||||||
materials = [None]
|
|
||||||
material_names = [name_compat(None)]
|
|
||||||
# Sort by Material, then images
|
|
||||||
# so we dont over context switch in the obj file.
|
|
||||||
if faceuv:
|
|
||||||
face_index_pairs.sort(key=lambda a: (a[0].material_index, hash(uv_texture[a[1]].image), a[0].use_smooth))
|
|
||||||
elif len(materials) > 1:
|
|
||||||
face_index_pairs.sort(key=lambda a: (a[0].material_index, a[0].use_smooth))
|
|
||||||
else:
|
|
||||||
# no materials
|
|
||||||
face_index_pairs.sort(key=lambda a: a[0].use_smooth)
|
|
||||||
# Set the default mat to no material and no image.
|
|
||||||
contextMat = 0, 0 # Can never be this, so we will label a new material the first chance we get.
|
|
||||||
contextSmooth = None # Will either be true or false, set bad to force initialization switch.
|
|
||||||
# use : blen obs ??? what is this ....
|
|
||||||
if True:
|
|
||||||
name1 = ob.name
|
|
||||||
name2 = ob.data.name
|
|
||||||
if name1 == name2:
|
|
||||||
obnamestring = name_compat(name1)
|
|
||||||
else:
|
|
||||||
obnamestring = '%s_%s' % (name_compat(name1), name_compat(name2))
|
|
||||||
fw('\t%s\n' % obnamestring) # Write Object name
|
|
||||||
###########################################################
|
|
||||||
## Vert
|
|
||||||
###########################################################
|
|
||||||
fw('\t\tVertex : %d\n\t\t\t' % len(me_verts))
|
|
||||||
for v in me_verts:
|
|
||||||
fw('%.6f %.6f %.6f|' % v.co[:])
|
|
||||||
fw('\n')
|
|
||||||
###########################################################
|
|
||||||
## UV
|
|
||||||
###########################################################
|
|
||||||
fw('\t\tUV-mapping :\n\t\t\t')
|
|
||||||
if faceuv:
|
|
||||||
# in case removing some of these dont get defined.
|
|
||||||
uv = uvkey = uv_dict = f_index = uv_index = None
|
|
||||||
uv_face_mapping = [None] * len(face_index_pairs)
|
|
||||||
uv_dict = {} # could use a set() here
|
|
||||||
for f, f_index in face_index_pairs:
|
|
||||||
uv_ls = uv_face_mapping[f_index] = []
|
|
||||||
for uv_index, l_index in enumerate(f.loop_indices):
|
|
||||||
uv = uv_layer[l_index].uv
|
|
||||||
uvkey = veckey2d(uv)
|
|
||||||
try:
|
|
||||||
uv_k = uv_dict[uvkey]
|
|
||||||
except:
|
|
||||||
uv_k = uv_dict[uvkey] = len(uv_dict)
|
|
||||||
fw('%.6f %.6f|' % uv[:])
|
|
||||||
uv_ls.append(uv_k)
|
|
||||||
uv_unique_count = len(uv_dict)
|
|
||||||
del uv, uvkey, uv_dict, f_index, uv_index, uv_ls, uv_k
|
|
||||||
# Only need uv_unique_count and uv_face_mapping
|
|
||||||
fw('\n')
|
|
||||||
###########################################################
|
|
||||||
## NORMAL
|
|
||||||
###########################################################
|
|
||||||
if f.use_smooth:
|
|
||||||
localIsSmooth = 'vertex'
|
|
||||||
else:
|
|
||||||
localIsSmooth = 'face'
|
|
||||||
fw('\t\tNormal(%s) : %d\n\t\t\t' % (localIsSmooth, len(face_index_pairs)) )
|
|
||||||
for f, f_index in face_index_pairs:
|
|
||||||
if f.use_smooth:
|
|
||||||
for v_idx in f.vertices:
|
|
||||||
v = me_verts[v_idx]
|
|
||||||
noKey = veckey3d(v.normal)
|
|
||||||
if noKey not in globalNormals:
|
|
||||||
globalNormals[noKey] = totno
|
|
||||||
totno += 1
|
|
||||||
fw('%.6f %.6f %.6f|' % noKey)
|
|
||||||
else:
|
|
||||||
# Hard, 1 normal from the face.
|
|
||||||
noKey = veckey3d(f.normal)
|
|
||||||
if noKey not in globalNormals:
|
|
||||||
globalNormals[noKey] = totno
|
|
||||||
totno += 1
|
|
||||||
fw('%.6f %.6f %.6f|' % noKey)
|
|
||||||
|
|
||||||
fw('\n')
|
|
||||||
if not faceuv:
|
|
||||||
f_image = None
|
|
||||||
###########################################################
|
|
||||||
## faces
|
|
||||||
###########################################################
|
|
||||||
fw('\t\tFace : %d' % len(face_index_pairs))
|
|
||||||
for f, f_index in face_index_pairs:
|
|
||||||
f_smooth = f.use_smooth
|
|
||||||
f_mat = min(f.material_index, len(materials) - 1)
|
|
||||||
if faceuv:
|
|
||||||
tface = uv_texture[f_index]
|
|
||||||
f_image = tface.image
|
|
||||||
# MAKE KEY
|
|
||||||
if faceuv and f_image: # Object is always true.
|
|
||||||
key = material_names[f_mat], f_image.name
|
|
||||||
else:
|
|
||||||
key = material_names[f_mat], None # No image, use None instead.
|
|
||||||
# CHECK FOR CONTEXT SWITCH
|
|
||||||
if key == contextMat:
|
|
||||||
pass # Context already switched, dont do anything
|
|
||||||
else:
|
|
||||||
if key[0] is None and key[1] is None:
|
|
||||||
# inform the use of a material :
|
|
||||||
fw("\n\t\t\t---:") # mat, image
|
|
||||||
else:
|
|
||||||
mat_data = mtl_dict.get(key)
|
|
||||||
if not mat_data:
|
|
||||||
# First add to global dict so we can export to mtl
|
|
||||||
# Then write mtl
|
|
||||||
# Make a new names from the mat and image name,
|
|
||||||
# converting any spaces to underscores with name_compat.
|
|
||||||
# If none image dont bother adding it to the name
|
|
||||||
# Try to avoid as much as possible adding texname (or other things)
|
|
||||||
# to the mtl name (see [#32102])...
|
|
||||||
mtl_name = "%s" % name_compat(key[0])
|
|
||||||
if mtl_rev_dict.get(mtl_name, None) not in {key, None}:
|
|
||||||
if key[1] is None:
|
|
||||||
tmp_ext = "_NONE"
|
|
||||||
else:
|
|
||||||
tmp_ext = "_%s" % name_compat(key[1])
|
|
||||||
i = 0
|
|
||||||
while mtl_rev_dict.get(mtl_name + tmp_ext, None) not in {key, None}:
|
|
||||||
i += 1
|
|
||||||
tmp_ext = "_%3d" % i
|
|
||||||
mtl_name += tmp_ext
|
|
||||||
mat_data = mtl_dict[key] = mtl_name, materials[f_mat], f_image
|
|
||||||
mtl_rev_dict[mtl_name] = key
|
|
||||||
# set the use of a material :
|
|
||||||
fw("\n\t\t\t%s\n\t\t\t\t" % mat_data[0]) # can be mat_image or (null)
|
|
||||||
contextMat = key
|
|
||||||
f_v = [(vi, me_verts[v_idx]) for vi, v_idx in enumerate(f.vertices)]
|
|
||||||
if faceuv:
|
|
||||||
# export the normals :
|
|
||||||
if f_smooth: # Smoothed, use vertex normals
|
|
||||||
for vi, v in f_v:
|
|
||||||
fw(" %d/%d/%d" %
|
|
||||||
(v.index + totverts-1,
|
|
||||||
totuvco + uv_face_mapping[f_index][vi]-1,
|
|
||||||
globalNormals[veckey3d(v.normal)]-1,
|
|
||||||
)) # vert, uv, normal
|
|
||||||
else: # No smoothing, face normals
|
|
||||||
no = globalNormals[veckey3d(f.normal)]
|
|
||||||
for vi, v in f_v:
|
|
||||||
fw(" %d/%d/%d" %
|
|
||||||
(v.index + totverts-1,
|
|
||||||
totuvco + uv_face_mapping[f_index][vi]-1,
|
|
||||||
no-1,
|
|
||||||
)) # vert, uv, normal
|
|
||||||
face_vert_index += len(f_v)
|
|
||||||
else: # No UV's
|
|
||||||
# export the normals :
|
|
||||||
if f_smooth: # Smoothed, use vertex normals
|
|
||||||
for vi, v in f_v:
|
|
||||||
fw(" %d//%d" % (
|
|
||||||
v.index + totverts-1,
|
|
||||||
globalNormals[veckey3d(v.normal)]-1,
|
|
||||||
))
|
|
||||||
else: # No smoothing, face normals
|
|
||||||
no = globalNormals[veckey3d(f.normal)]
|
|
||||||
for vi, v in f_v:
|
|
||||||
fw(" %d//%d" % (v.index + totverts-1, no-1))
|
|
||||||
fw('|')
|
|
||||||
fw('\n')
|
|
||||||
# Write edges. ==> did not know what it is ...
|
|
||||||
#fw('Faces : %d' % len(edges))
|
|
||||||
#for ed in edges:
|
|
||||||
# if ed.is_loose:
|
|
||||||
# fw('%d %d\n' % (ed.vertices[0] + totverts, ed.vertices[1] + totverts))
|
|
||||||
|
|
||||||
# Make the indices global rather then per mesh
|
|
||||||
totverts += len(me_verts)
|
|
||||||
if faceuv:
|
|
||||||
totuvco += uv_unique_count
|
|
||||||
# clean up
|
|
||||||
bpy.data.meshes.remove(me)
|
|
||||||
if ob_main.dupli_type != 'NONE':
|
|
||||||
ob_main.dupli_list_clear()
|
|
||||||
#####################################################################
|
|
||||||
## Save collision shapes (for one object :
|
|
||||||
#####################################################################
|
|
||||||
for subObj in getChildren(ob_main):
|
|
||||||
print(" child : '%s'" % (subObj.name))
|
|
||||||
if subObj.name.lower().startswith(EXPORT_COLLISION_NAME):
|
|
||||||
print(" find physics : '%s'" % (subObj.name))
|
|
||||||
writeCollisionShape(subObj, file, ob_main.scale)
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
## Now we have all our materials, save them in the material section
|
|
||||||
#####################################################################
|
|
||||||
write_mtl(scene, file, mtlfilepath, EXPORT_PATH_MODE, copy_set, mtl_dict)
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
## End of the file generation:
|
|
||||||
#####################################################################
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
# copy all collected files.
|
|
||||||
bpy_extras.io_utils.path_reference_copy(copy_set)
|
|
||||||
|
|
||||||
print("EMF Export time: %.2f" % (time.time() - time1))
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
" @brief generate the requested object file ... with his material inside and ...
|
|
||||||
"
|
|
||||||
"""
|
|
||||||
def _write(context,
|
|
||||||
filepath,
|
|
||||||
EXPORT_SEL_ONLY,
|
|
||||||
EXPORT_GLOBAL_MATRIX,
|
|
||||||
EXPORT_PATH_MODE,
|
|
||||||
EXPORT_BINARY_MODE,
|
|
||||||
EXPORT_COLLISION_NAME,
|
|
||||||
):
|
|
||||||
#
|
|
||||||
base_name, ext = os.path.splitext(filepath)
|
|
||||||
# create the output name :
|
|
||||||
context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension
|
|
||||||
# get the curent scene :
|
|
||||||
scene = context.scene
|
|
||||||
# Exit edit mode before exporting, so current object states are exported properly.
|
|
||||||
if bpy.ops.object.mode_set.poll():
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
|
||||||
# get the curent frame selected :
|
|
||||||
frame = scene.frame_current
|
|
||||||
# Loop through all frames in the scene and export.
|
|
||||||
scene.frame_set(frame, 0.0)
|
|
||||||
# get only the object that are selected or all ...
|
|
||||||
if EXPORT_SEL_ONLY:
|
|
||||||
objects = context.selected_objects
|
|
||||||
else:
|
|
||||||
objects = scene.objects
|
|
||||||
|
|
||||||
full_path = ''.join(context_name)
|
|
||||||
|
|
||||||
write_file(full_path,
|
|
||||||
objects,
|
|
||||||
scene,
|
|
||||||
EXPORT_GLOBAL_MATRIX,
|
|
||||||
EXPORT_PATH_MODE,
|
|
||||||
EXPORT_BINARY_MODE,
|
|
||||||
EXPORT_COLLISION_NAME,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
" @brief Save the current element in the file requested.
|
|
||||||
"
|
|
||||||
"""
|
|
||||||
def save(operator,
|
|
||||||
context,
|
|
||||||
filepath="",
|
|
||||||
use_selection=True,
|
|
||||||
use_binary=False,
|
|
||||||
collision_object_name="",
|
|
||||||
global_matrix=None,
|
|
||||||
path_mode='AUTO'
|
|
||||||
):
|
|
||||||
_write(context,
|
|
||||||
filepath,
|
|
||||||
EXPORT_SEL_ONLY=use_selection,
|
|
||||||
EXPORT_GLOBAL_MATRIX=global_matrix,
|
|
||||||
EXPORT_PATH_MODE=path_mode,
|
|
||||||
EXPORT_BINARY_MODE=use_binary,
|
|
||||||
EXPORT_COLLISION_NAME=collision_object_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
return {'FINISHED'}
|
|
2
external/ege
vendored
2
external/ege
vendored
@ -1 +1 @@
|
|||||||
Subproject commit b2a3095a2edb8c6cde490a0c80de4973c22d432b
|
Subproject commit a617216d054368eb6ebeb8c6c248c07788ab1a69
|
Loading…
x
Reference in New Issue
Block a user