Sun position: Fix T80379 - Custom startup breaks the add-on
[blender-addons.git] / object_print3d_utils / export.py
blobfc225cccbecc7c0bbc98c0184109ff18f5dcf2c1
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.
24 import bpy
27 def image_get(mat):
28 from bpy_extras import node_shader_utils
30 if mat.use_nodes:
31 mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat)
32 base_color_tex = mat_wrap.base_color_texture
33 if base_color_tex and base_color_tex.image:
34 return base_color_tex.image
37 def image_copy_guess(filepath, objects):
38 # 'filepath' is the path we are writing to.
39 image = None
40 mats = set()
42 for obj in objects:
43 for slot in obj.material_slots:
44 if slot.material:
45 mats.add(slot.material)
47 for mat in mats:
48 image = image_get(mat)
49 if image is not None:
50 break
52 if image is not None:
53 import os
54 import shutil
56 imagepath = bpy.path.abspath(image.filepath, library=image.library)
57 if os.path.exists(imagepath):
58 filepath_noext = os.path.splitext(filepath)[0]
59 ext = os.path.splitext(imagepath)[1]
61 imagepath_dst = filepath_noext + ext
62 print(f"copying texture: {imagepath!r} -> {imagepath_dst!r}")
64 try:
65 shutil.copy(imagepath, imagepath_dst)
66 except:
67 import traceback
68 traceback.print_exc()
71 def write_mesh(context, report_cb):
72 import os
74 scene = context.scene
75 layer = context.view_layer
76 unit = scene.unit_settings
77 print_3d = scene.print_3d
79 export_format = print_3d.export_format
80 global_scale = unit.scale_length if (unit.system != 'NONE' and print_3d.use_apply_scale) else 1.0
81 path_mode = 'COPY' if print_3d.use_export_texture else 'AUTO'
82 export_path = bpy.path.abspath(print_3d.export_path)
83 obj = layer.objects.active
85 # Create name 'export_path/blendname-objname'
86 # add the filename component
87 if bpy.data.is_saved:
88 name = os.path.basename(bpy.data.filepath)
89 name = os.path.splitext(name)[0]
90 else:
91 name = "untitled"
93 # add object name
94 name += f"-{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 filepath=filepath,
122 ascii=False,
123 use_mesh_modifiers=True,
124 use_selection=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 filepath=filepath,
132 use_mesh_modifiers=True,
133 use_selection=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 filepath=filepath,
141 use_mesh_modifiers=True,
142 use_selection=True,
143 path_mode=path_mode,
144 global_scale=global_scale,
146 elif export_format == 'OBJ':
147 addon_ensure("io_scene_obj")
148 filepath = bpy.path.ensure_ext(filepath, ".obj")
149 ret = bpy.ops.export_scene.obj(
150 filepath=filepath,
151 use_mesh_modifiers=True,
152 use_selection=True,
153 path_mode=path_mode,
154 global_scale=global_scale,
156 else:
157 assert 0
159 # for formats that don't support images
160 if export_format in {'STL', 'PLY'}:
161 if path_mode == 'COPY':
162 image_copy_guess(filepath, context.selected_objects)
164 if 'FINISHED' in ret:
165 if report_cb is not None:
166 report_cb({'INFO'}, f"Exported: {filepath!r}")
168 return True
170 if report_cb is not None:
171 report_cb({'ERROR'}, "Export failed")
173 return False