option to apply scale on export. also add global scale options for exporters. OBJ...
[blender-addons.git] / object_print3d_utils / export.py
blobd0eeca3f186028a6a83ee5b60805c5b3feca2487
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # <pep8-80 compliant>
21 # Export wrappers and integration with external tools.
23 import bpy
24 import os
27 def image_copy_guess(filepath, objects):
28 # 'filepath' is the path we are writing to.
29 import shutil
30 from bpy_extras import object_utils
31 image = None
32 for obj in objects:
33 image = object_utils.object_image_guess(obj)
34 if image is not None:
35 break
37 if image is not None:
38 imagepath = bpy.path.abspath(image.filepath, library=image.library)
39 if os.path.exists(imagepath):
40 filepath_noext = os.path.splitext(filepath)[0]
41 ext = os.path.splitext(imagepath)[1]
43 imagepath_dst = filepath_noext + ext
44 print("copying texture: %r -> %r" % (imagepath, imagepath_dst))
45 try:
46 shutil.copy(imagepath, imagepath_dst)
47 except:
48 import traceback
49 traceback.print_exc()
52 def write_mesh(context, info, report_cb):
53 scene = context.scene
54 unit = scene.unit_settings
55 print_3d = scene.print_3d
57 obj_base = scene.object_bases.active
58 obj = obj_base.object
60 export_format = print_3d.export_format
61 global_scale = unit.scale_length if (unit.system != 'NONE' and print_3d.use_apply_scale) else 1.0
62 path_mode = 'COPY' if print_3d.use_export_texture else 'AUTO'
64 context_override = context.copy()
66 obj_base_tmp = None
68 # PLY can only export single mesh objects!
69 if export_format == 'PLY':
70 context_backup = context.copy()
71 bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
73 from . import mesh_helpers
74 obj_base_tmp = mesh_helpers.object_merge(context, context_override["selected_objects"])
75 context_override["active_object"] = obj_base_tmp.object
76 context_override["selected_bases"] = [obj_base_tmp]
77 context_override["selected_objects"] = [obj_base_tmp.object]
78 else:
79 if obj_base not in context_override["selected_bases"]:
80 context_override["selected_bases"].append(obj_base)
81 if obj not in context_override["selected_objects"]:
82 context_override["selected_objects"].append(obj)
84 export_path = bpy.path.abspath(print_3d.export_path)
86 # Create name 'export_path/blendname-objname'
87 # add the filename component
88 if bpy.data.is_saved:
89 name = os.path.basename(bpy.data.filepath)
90 name = os.path.splitext(name)[0]
91 else:
92 name = "untitled"
93 # add object name
94 name += "-%s" % bpy.path.clean_name(obj.name)
96 # first ensure the path is created
97 if export_path:
98 # this can fail with strange errors,
99 # if the dir cant be made then we get an error later.
100 try:
101 os.makedirs(export_path, exist_ok=True)
102 except:
103 import traceback
104 traceback.print_exc()
106 filepath = os.path.join(export_path, name)
108 # ensure addon is enabled
109 import addon_utils
111 def addon_ensure(addon_id):
112 # Enable the addon, dont change preferences.
113 default_state, loaded_state = addon_utils.check(addon_id)
114 if not loaded_state:
115 addon_utils.enable(addon_id, default_set=False)
117 if export_format == 'STL':
118 addon_ensure("io_mesh_stl")
119 filepath = bpy.path.ensure_ext(filepath, ".stl")
120 ret = bpy.ops.export_mesh.stl(
121 context_override,
122 filepath=filepath,
123 ascii=False,
124 use_mesh_modifiers=True,
125 global_scale=global_scale,
127 elif export_format == 'PLY':
128 addon_ensure("io_mesh_ply")
129 filepath = bpy.path.ensure_ext(filepath, ".ply")
130 ret = bpy.ops.export_mesh.ply(
131 context_override,
132 filepath=filepath,
133 use_mesh_modifiers=True,
134 global_scale=global_scale,
136 elif export_format == 'X3D':
137 addon_ensure("io_scene_x3d")
138 filepath = bpy.path.ensure_ext(filepath, ".x3d")
139 ret = bpy.ops.export_scene.x3d(
140 context_override,
141 filepath=filepath,
142 use_mesh_modifiers=True,
143 use_selection=True,
144 path_mode=path_mode,
145 global_scale=global_scale,
147 elif export_format == 'WRL':
148 addon_ensure("io_scene_vrml2")
149 filepath = bpy.path.ensure_ext(filepath, ".wrl")
150 ret = bpy.ops.export_scene.vrml2(
151 context_override,
152 filepath=filepath,
153 use_mesh_modifiers=True,
154 use_selection=True,
155 path_mode=path_mode,
156 global_scale=global_scale,
158 elif export_format == 'OBJ':
159 addon_ensure("io_scene_obj")
160 filepath = bpy.path.ensure_ext(filepath, ".obj")
161 ret = bpy.ops.export_scene.obj(
162 context_override,
163 filepath=filepath,
164 use_mesh_modifiers=True,
165 use_selection=True,
166 path_mode=path_mode,
167 global_scale=global_scale,
169 else:
170 assert(0)
172 # for formats that don't support images
173 if export_format in {'STL', 'PLY'}:
174 if path_mode == 'COPY':
175 image_copy_guess(filepath, context_override["selected_objects"])
177 if obj_base_tmp is not None:
178 obj = obj_base_tmp.object
179 mesh = obj.data
180 scene.objects.unlink(obj)
181 bpy.data.objects.remove(obj)
182 bpy.data.meshes.remove(mesh)
183 del obj_base_tmp, obj, mesh
185 # restore context
186 base = None
187 for base in context_backup["selected_bases"]:
188 base.select = True
189 del base
190 scene.objects.active = context_backup["active_object"]
192 if 'FINISHED' in ret:
193 info.append(("%r ok" % os.path.basename(filepath), None))
195 if report_cb is not None:
196 report_cb({'INFO'}, "Exported: %r" % filepath)
197 return True
198 else:
199 info.append(("%r fail" % os.path.basename(filepath), None))
200 return False