glTF exporter: add glTF Embedded format option back - with option
[blender-addons.git] / io_scene_gltf2 / blender / exp / gltf2_blender_export.py
blob2408b25fd54e55be78ec8a5ff572861189883a80
1 # SPDX-FileCopyrightText: 2018-2021 The glTF-Blender-IO authors
3 # SPDX-License-Identifier: Apache-2.0
5 import os
6 import subprocess
7 import time
9 import bpy
10 import sys
11 import traceback
13 from ...io.com.gltf2_io_debug import print_console, print_newline
14 from ...io.exp import gltf2_io_export
15 from ...io.exp import gltf2_io_draco_compression_extension
16 from ...io.exp.gltf2_io_user_extensions import export_user_extensions
17 from ..com import gltf2_blender_json
18 from . import gltf2_blender_gather
19 from .gltf2_blender_gltf2_exporter import GlTF2Exporter
20 from .gltf2_blender_gltf2_exporter import fix_json
23 def save(context, export_settings):
24 """Start the glTF 2.0 export and saves to content either to a .gltf or .glb file."""
25 if bpy.context.active_object is not None:
26 if bpy.context.active_object.mode != "OBJECT": # For linked object, you can't force OBJECT mode
27 bpy.ops.object.mode_set(mode='OBJECT')
29 original_frame = bpy.context.scene.frame_current
30 if not export_settings['gltf_current_frame']:
31 bpy.context.scene.frame_set(0)
33 __notify_start(context)
34 start_time = time.time()
35 pre_export_callbacks = export_settings["pre_export_callbacks"]
36 for callback in pre_export_callbacks:
37 callback(export_settings)
39 json, buffer = __export(export_settings)
41 post_export_callbacks = export_settings["post_export_callbacks"]
42 for callback in post_export_callbacks:
43 callback(export_settings)
44 __write_file(json, buffer, export_settings)
46 end_time = time.time()
47 __notify_end(context, end_time - start_time)
49 if not export_settings['gltf_current_frame']:
50 bpy.context.scene.frame_set(int(original_frame))
51 return {'FINISHED'}
54 def __export(export_settings):
55 exporter = GlTF2Exporter(export_settings)
56 __gather_gltf(exporter, export_settings)
57 buffer = __create_buffer(exporter, export_settings)
58 exporter.finalize_images()
60 export_user_extensions('gather_gltf_extensions_hook', export_settings, exporter.glTF)
61 exporter.traverse_extensions()
63 # now that addons possibly add some fields in json, we can fix in needed
64 json = fix_json(exporter.glTF.to_dict())
66 # Convert additional data if needed
67 if export_settings['gltf_unused_textures'] is True:
68 additional_json_textures = fix_json([i.to_dict() for i in exporter.additional_data.additional_textures])
70 # Now that we have the final json, we can add the additional data
71 # We can not do that for all people, because we don't want this extra to become "a standard"
72 # So let's use the "extras" field filled by a user extension
74 export_user_extensions('gather_gltf_additional_textures_hook', export_settings, json, additional_json_textures)
76 # if len(additional_json_textures) > 0:
77 # if json.get('extras') is None:
78 # json['extras'] = {}
79 # json['extras']['additionalTextures'] = additional_json_textures
81 return json, buffer
84 def __gather_gltf(exporter, export_settings):
85 active_scene_idx, scenes, animations = gltf2_blender_gather.gather_gltf2(export_settings)
87 unused_skins = export_settings['vtree'].get_unused_skins()
89 if export_settings['gltf_draco_mesh_compression']:
90 gltf2_io_draco_compression_extension.encode_scene_primitives(scenes, export_settings)
91 exporter.add_draco_extension()
93 export_user_extensions('gather_gltf_hook', export_settings, active_scene_idx, scenes, animations)
95 for idx, scene in enumerate(scenes):
96 exporter.add_scene(scene, idx==active_scene_idx, export_settings=export_settings)
97 for animation in animations:
98 exporter.add_animation(animation)
99 exporter.manage_gpu_instancing_nodes(export_settings)
100 exporter.traverse_unused_skins(unused_skins)
101 exporter.traverse_additional_textures()
102 exporter.traverse_additional_images()
105 def __create_buffer(exporter, export_settings):
106 buffer = bytes()
107 if export_settings['gltf_format'] == 'GLB':
108 buffer = exporter.finalize_buffer(export_settings['gltf_filedirectory'], is_glb=True)
109 else:
110 if export_settings['gltf_format'] == 'GLTF_EMBEDDED':
111 exporter.finalize_buffer(export_settings['gltf_filedirectory'])
112 else:
113 exporter.finalize_buffer(export_settings['gltf_filedirectory'],
114 export_settings['gltf_binaryfilename'])
116 return buffer
118 def __postprocess_with_gltfpack(export_settings):
120 gltfpack_binary_file_path = bpy.context.preferences.addons['io_scene_gltf2'].preferences.gltfpack_path_ui
122 gltf_file_path = export_settings['gltf_filepath']
123 gltf_file_base = os.path.splitext(os.path.basename(gltf_file_path))[0]
124 gltf_file_extension = os.path.splitext(os.path.basename(gltf_file_path))[1]
125 gltf_file_directory = os.path.dirname(gltf_file_path)
126 gltf_output_file_directory = os.path.join(gltf_file_directory, "gltfpacked")
127 if (os.path.exists(gltf_output_file_directory) is False):
128 os.makedirs(gltf_output_file_directory)
130 gltf_input_file_path = gltf_file_path
131 gltf_output_file_path = os.path.join(gltf_output_file_directory, gltf_file_base + gltf_file_extension)
133 options = []
135 if (export_settings['gltf_gltfpack_tc']):
136 options.append("-tc")
138 if (export_settings['gltf_gltfpack_tq']):
139 options.append("-tq")
140 options.append(f"{export_settings['gltf_gltfpack_tq']}")
142 if (export_settings['gltf_gltfpack_si'] != 1.0):
143 options.append("-si")
144 options.append(f"{export_settings['gltf_gltfpack_si']}")
146 if (export_settings['gltf_gltfpack_sa']):
147 options.append("-sa")
149 if (export_settings['gltf_gltfpack_slb']):
150 options.append("-slb")
152 if (export_settings['gltf_gltfpack_noq']):
153 options.append("-noq")
154 else:
155 options.append("-vp")
156 options.append(f"{export_settings['gltf_gltfpack_vp']}")
157 options.append("-vt")
158 options.append(f"{export_settings['gltf_gltfpack_vt']}")
159 options.append("-vn")
160 options.append(f"{export_settings['gltf_gltfpack_vn']}")
161 options.append("-vc")
162 options.append(f"{export_settings['gltf_gltfpack_vc']}")
164 match export_settings['gltf_gltfpack_vpi']:
165 case "Integer":
166 options.append("-vpi")
167 case "Normalized":
168 options.append("-vpn")
169 case "Floating-point":
170 options.append("-vpf")
172 parameters = []
173 parameters.append("-i")
174 parameters.append(gltf_input_file_path)
175 parameters.append("-o")
176 parameters.append(gltf_output_file_path)
178 try:
179 subprocess.run([gltfpack_binary_file_path] + options + parameters, check=True)
180 except subprocess.CalledProcessError as e:
181 print_console('ERROR', "Calling gltfpack was not successful")
183 def __write_file(json, buffer, export_settings):
184 try:
185 gltf2_io_export.save_gltf(
186 json,
187 export_settings,
188 gltf2_blender_json.BlenderJSONEncoder,
189 buffer)
190 if (export_settings['gltf_use_gltfpack'] == True):
191 __postprocess_with_gltfpack(export_settings)
193 except AssertionError as e:
194 _, _, tb = sys.exc_info()
195 traceback.print_tb(tb) # Fixed format
196 tb_info = traceback.extract_tb(tb)
197 for tbi in tb_info:
198 filename, line, func, text = tbi
199 print_console('ERROR', 'An error occurred on line {} in statement {}'.format(line, text))
200 print_console('ERROR', str(e))
201 raise e
204 def __notify_start(context):
205 print_console('INFO', 'Starting glTF 2.0 export')
206 context.window_manager.progress_begin(0, 100)
207 context.window_manager.progress_update(0)
210 def __notify_end(context, elapsed):
211 print_console('INFO', 'Finished glTF 2.0 export in {} s'.format(elapsed))
212 context.window_manager.progress_end()
213 print_newline()