1 # SPDX-FileCopyrightText: 2013-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # Export wrappers and integration with external tools.
10 from bpy
.app
.translations
import (
12 pgettext_data
as data_
,
17 from bpy_extras
import node_shader_utils
20 mat_wrap
= node_shader_utils
.PrincipledBSDFWrapper(mat
)
21 base_color_tex
= mat_wrap
.base_color_texture
22 if base_color_tex
and base_color_tex
.image
:
23 return base_color_tex
.image
26 def image_copy_guess(filepath
, objects
):
27 # 'filepath' is the path we are writing to.
32 for slot
in obj
.material_slots
:
34 mats
.add(slot
.material
)
37 image
= image_get(mat
)
45 imagepath
= bpy
.path
.abspath(image
.filepath
, library
=image
.library
)
46 if os
.path
.exists(imagepath
):
47 filepath_noext
= os
.path
.splitext(filepath
)[0]
48 ext
= os
.path
.splitext(imagepath
)[1]
50 imagepath_dst
= filepath_noext
+ ext
51 print(f
"copying texture: {imagepath!r} -> {imagepath_dst!r}")
54 shutil
.copy(imagepath
, imagepath_dst
)
60 def write_mesh(context
, report_cb
):
64 layer
= context
.view_layer
65 unit
= scene
.unit_settings
66 print_3d
= scene
.print_3d
68 export_format
= print_3d
.export_format
69 global_scale
= unit
.scale_length
if (unit
.system
!= 'NONE' and print_3d
.use_apply_scale
) else 1.0
70 path_mode
= 'COPY' if print_3d
.use_export_texture
else 'AUTO'
71 export_path
= bpy
.path
.abspath(print_3d
.export_path
)
72 obj
= layer
.objects
.active
73 export_data_layers
= print_3d
.use_data_layers
75 # Create name 'export_path/blendname-objname'
76 # add the filename component
78 name
= os
.path
.basename(bpy
.data
.filepath
)
79 name
= os
.path
.splitext(name
)[0]
81 name
= data_("untitled")
85 name
+= "-" + re
.sub(r
'[\\/:*?"<>|]', "", obj
.name
)
87 # first ensure the path is created
89 # this can fail with strange errors,
90 # if the dir can't be made then we get an error later.
92 os
.makedirs(export_path
, exist_ok
=True)
97 filepath
= os
.path
.join(export_path
, name
)
99 # ensure addon is enabled
102 def addon_ensure(addon_id
):
103 # Enable the addon, dont change preferences.
104 _default_state
, loaded_state
= addon_utils
.check(addon_id
)
106 addon_utils
.enable(addon_id
, default_set
=False)
108 if export_format
== 'STL':
109 addon_ensure("io_mesh_stl")
110 filepath
= bpy
.path
.ensure_ext(filepath
, ".stl")
111 ret
= bpy
.ops
.export_mesh
.stl(
114 use_mesh_modifiers
=True,
116 global_scale
=global_scale
,
118 elif export_format
== 'PLY':
119 filepath
= bpy
.path
.ensure_ext(filepath
, ".ply")
120 ret
= bpy
.ops
.wm
.ply_export(
123 apply_modifiers
=True,
124 export_selected_objects
=True,
125 global_scale
=global_scale
,
126 export_normals
=export_data_layers
,
127 export_uv
=export_data_layers
,
128 export_colors
="SRGB" if export_data_layers
else "NONE",
130 elif export_format
== 'X3D':
131 addon_ensure("io_scene_x3d")
132 filepath
= bpy
.path
.ensure_ext(filepath
, ".x3d")
133 ret
= bpy
.ops
.export_scene
.x3d(
135 use_mesh_modifiers
=True,
137 global_scale
=global_scale
,
139 use_normals
=export_data_layers
,
141 elif export_format
== 'OBJ':
142 filepath
= bpy
.path
.ensure_ext(filepath
, ".obj")
143 ret
= bpy
.ops
.wm
.obj_export(
145 apply_modifiers
=True,
146 export_selected_objects
=True,
147 global_scale
=global_scale
,
149 export_normals
=export_data_layers
,
150 export_uv
=export_data_layers
,
151 export_materials
=export_data_layers
,
152 export_colors
=export_data_layers
,
157 # for formats that don't support images
158 if path_mode
== 'COPY' and export_format
in {'STL', 'PLY'}:
159 image_copy_guess(filepath
, context
.selected_objects
)
161 if 'FINISHED' in ret
:
162 if report_cb
is not None:
163 report_cb({'INFO'}, tip_("Exported: {!r}").format(filepath
))
167 if report_cb
is not None:
168 report_cb({'ERROR'}, "Export failed")