1/**************************************************************************/
2/* editor_scene_importer_fbx.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "editor_scene_importer_fbx.h"
32
33#ifdef TOOLS_ENABLED
34
35#include "../gltf_document.h"
36
37#include "core/config/project_settings.h"
38#include "editor/editor_settings.h"
39#include "main/main.h"
40
41uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
42 return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
43}
44
45void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) const {
46 r_extensions->push_back("fbx");
47}
48
49Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags,
50 const HashMap<StringName, Variant> &p_options,
51 List<String> *r_missing_deps, Error *r_err) {
52 // Get global paths for source and sink.
53
54 // Don't use `c_escape()` as it can generate broken paths. These paths will be
55 // enclosed in double quotes by OS::execute(), so we only need to escape those.
56 // `c_escape_multiline()` seems to do this (escapes `\` and `"` only).
57 const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline();
58 const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
59 vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text()));
60 const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline();
61
62 // Run fbx2gltf.
63
64 String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path");
65
66 List<String> args;
67 args.push_back("--pbr-metallic-roughness");
68 args.push_back("--input");
69 args.push_back(source_global);
70 args.push_back("--output");
71 args.push_back(sink_global);
72 args.push_back("--binary");
73
74 String standard_out;
75 int ret;
76 OS::get_singleton()->execute(fbx2gltf_path, args, &standard_out, &ret, true);
77 print_verbose(fbx2gltf_path);
78 print_verbose(standard_out);
79
80 if (ret != 0) {
81 if (r_err) {
82 *r_err = ERR_SCRIPT_FAILED;
83 }
84 ERR_PRINT(vformat("FBX conversion to glTF failed with error: %d.", ret));
85 return nullptr;
86 }
87
88 // Import the generated glTF.
89
90 // Use GLTFDocument instead of glTF importer to keep image references.
91 Ref<GLTFDocument> gltf;
92 gltf.instantiate();
93 Ref<GLTFState> state;
94 state.instantiate();
95 print_verbose(vformat("glTF path: %s", sink));
96 Error err = gltf->append_from_file(sink, state, p_flags, p_path.get_base_dir());
97 if (err != OK) {
98 if (r_err) {
99 *r_err = FAILED;
100 }
101 return nullptr;
102 }
103
104#ifndef DISABLE_DEPRECATED
105 bool trimming = p_options.has("animation/trimming") ? (bool)p_options["animation/trimming"] : false;
106 bool remove_immutable = p_options.has("animation/remove_immutable_tracks") ? (bool)p_options["animation/remove_immutable_tracks"] : true;
107 return gltf->generate_scene(state, (float)p_options["animation/fps"], trimming, remove_immutable);
108#else
109 return gltf->generate_scene(state, (float)p_options["animation/fps"], (bool)p_options["animation/trimming"], (bool)p_options["animation/remove_immutable_tracks"]);
110#endif
111}
112
113Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation,
114 const String &p_option, const HashMap<StringName, Variant> &p_options) {
115 return true;
116}
117
118void EditorSceneFormatImporterFBX::get_import_options(const String &p_path,
119 List<ResourceImporter::ImportOption> *r_options) {
120}
121
122bool EditorFileSystemImportFormatSupportQueryFBX::is_active() const {
123 String fbx2gltf_path = EDITOR_GET("filesystem/import/fbx/fbx2gltf_path");
124 return !FileAccess::exists(fbx2gltf_path);
125}
126
127Vector<String> EditorFileSystemImportFormatSupportQueryFBX::get_file_extensions() const {
128 Vector<String> ret;
129 ret.push_back("fbx");
130 return ret;
131}
132
133bool EditorFileSystemImportFormatSupportQueryFBX::query() {
134 FBXImporterManager::get_singleton()->show_dialog(true);
135
136 while (true) {
137 OS::get_singleton()->delay_usec(1);
138 DisplayServer::get_singleton()->process_events();
139 Main::iteration();
140 if (!FBXImporterManager::get_singleton()->is_visible()) {
141 break;
142 }
143 }
144
145 return false;
146}
147
148#endif // TOOLS_ENABLED
149