Import scenes as AnimationLibrary

Added the ability to import scenes as AnimationLibrary

* Completes implementation of https://github.com/godotengine/godot-proposals/issues/4296
* Helps if you want to export animations to a separate file (say a GLTF) to avoid re-importing/exporting them every time the model changes.
* Helps if you simply want to have animations using a dummy model, which can be shared across multiple models.

Creates a secondary scene importer used only for animations.

**NOTE**: A new flag for scene importer: EditorSceneFormatImporter.IMPORT_DISCARD_MESHES_AND_MATERIALS has been added, to hint importers that they should skip meshes and animations (and hence make importing faster). It is not implemented in any importer yet, this should be done in a separate PR.
This commit is contained in:
reduz 2022-04-12 16:07:09 +02:00
parent 43f94c95aa
commit 66009318e0
20 changed files with 269 additions and 161 deletions

View file

@ -29,16 +29,8 @@
<method name="_get_option_visibility" qualifiers="virtual const">
<return type="Variant" />
<argument index="0" name="path" type="String" />
<argument index="1" name="option" type="String" />
<description>
</description>
</method>
<method name="_import_animation" qualifiers="virtual">
<return type="Animation" />
<argument index="0" name="path" type="String" />
<argument index="1" name="flags" type="int" />
<argument index="2" name="options" type="Dictionary" />
<argument index="3" name="bake_fps" type="int" />
<argument index="1" name="for_animation" type="bool" />
<argument index="2" name="option" type="String" />
<description>
</description>
</method>
@ -63,5 +55,7 @@
</constant>
<constant name="IMPORT_USE_NAMED_SKIN_BINDS" value="16">
</constant>
<constant name="IMPORT_DISCARD_MESHES_AND_MATERIALS" value="32">
</constant>
</constants>
</class>

View file

@ -34,7 +34,8 @@
<method name="_get_internal_option_visibility" qualifiers="virtual const">
<return type="Variant" />
<argument index="0" name="category" type="int" />
<argument index="1" name="option" type="String" />
<argument index="1" name="for_animation" type="bool" />
<argument index="2" name="option" type="String" />
<description>
Return true or false whether a given option should be visible. Return null to ignore.
</description>
@ -42,7 +43,8 @@
<method name="_get_option_visibility" qualifiers="virtual const">
<return type="Variant" />
<argument index="0" name="path" type="String" />
<argument index="1" name="option" type="String" />
<argument index="1" name="for_animation" type="bool" />
<argument index="2" name="option" type="String" />
<description>
Return true or false whether a given option should be visible. Return null to ignore.
</description>

View file

@ -5997,18 +5997,22 @@ EditorNode::EditorNode() {
import_scene.instantiate();
ResourceFormatImporter::get_singleton()->add_importer(import_scene);
Ref<ResourceImporterScene> import_animation;
import_animation = Ref<ResourceImporterScene>(memnew(ResourceImporterScene(true)));
ResourceFormatImporter::get_singleton()->add_importer(import_animation);
{
Ref<EditorSceneFormatImporterCollada> import_collada;
import_collada.instantiate();
import_scene->add_importer(import_collada);
ResourceImporterScene::add_importer(import_collada);
Ref<EditorOBJImporter> import_obj2;
import_obj2.instantiate();
import_scene->add_importer(import_obj2);
ResourceImporterScene::add_importer(import_obj2);
Ref<EditorSceneFormatImporterESCN> import_escn;
import_escn.instantiate();
import_scene->add_importer(import_escn);
ResourceImporterScene::add_importer(import_escn);
}
Ref<ResourceImporterBitMap> import_bitmap;
@ -7245,6 +7249,7 @@ EditorNode::EditorNode() {
EditorNode::~EditorNode() {
EditorInspector::cleanup_plugins();
EditorTranslationParser::get_singleton()->clean_parsers();
ResourceImporterScene::clean_up_importer_plugins();
remove_print_handler(&print_handler);
EditorHelp::cleanup_doc();

View file

@ -763,20 +763,20 @@ void EditorPlugin::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_p
void EditorPlugin::add_scene_format_importer_plugin(const Ref<EditorSceneFormatImporter> &p_importer, bool p_first_priority) {
ERR_FAIL_COND(!p_importer.is_valid());
ResourceImporterScene::get_singleton()->add_importer(p_importer, p_first_priority);
ResourceImporterScene::add_importer(p_importer, p_first_priority);
}
void EditorPlugin::remove_scene_format_importer_plugin(const Ref<EditorSceneFormatImporter> &p_importer) {
ERR_FAIL_COND(!p_importer.is_valid());
ResourceImporterScene::get_singleton()->remove_importer(p_importer);
ResourceImporterScene::remove_importer(p_importer);
}
void EditorPlugin::add_scene_post_import_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority) {
ResourceImporterScene::get_singleton()->add_post_importer_plugin(p_plugin, p_first_priority);
ResourceImporterScene::add_post_importer_plugin(p_plugin, p_first_priority);
}
void EditorPlugin::remove_scene_post_import_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin) {
ResourceImporterScene::get_singleton()->remove_post_importer_plugin(p_plugin);
ResourceImporterScene::remove_post_importer_plugin(p_plugin);
}
int find(const PackedStringArray &a, const String &v) {

View file

@ -989,7 +989,7 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
{
List<String> importer_exts;
ResourceImporterScene::get_singleton()->get_recognized_extensions(&importer_exts);
ResourceImporterScene::get_scene_singleton()->get_recognized_extensions(&importer_exts);
String extension = fpath.get_extension();
for (const String &E : importer_exts) {
if (extension.nocasecmp_to(E) == 0) {
@ -1000,7 +1000,27 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
}
if (is_imported) {
ResourceImporterScene::get_singleton()->show_advanced_options(fpath);
ResourceImporterScene::get_scene_singleton()->show_advanced_options(fpath);
} else {
EditorNode::get_singleton()->open_request(fpath);
}
} else if (ResourceLoader::get_resource_type(fpath) == "AnimationLibrary") {
bool is_imported = false;
{
List<String> importer_exts;
ResourceImporterScene::get_animation_singleton()->get_recognized_extensions(&importer_exts);
String extension = fpath.get_extension();
for (const String &E : importer_exts) {
if (extension.nocasecmp_to(E) == 0) {
is_imported = true;
break;
}
}
}
if (is_imported) {
ResourceImporterScene::get_animation_singleton()->show_advanced_options(fpath);
} else {
EditorNode::get_singleton()->open_request(fpath);
}

View file

@ -1817,26 +1817,5 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3
return state.scene;
}
Ref<Animation> EditorSceneFormatImporterCollada::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
ColladaImport state;
state.use_mesh_builtin_materials = false;
Error err = state.load(p_path, Collada::IMPORT_FLAG_ANIMATION, p_flags & EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS);
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'.");
state.create_animations(true);
if (state.scene) {
memdelete(state.scene);
}
if (state.animations.size() == 0) {
return Ref<Animation>();
}
Ref<Animation> anim = state.animations[0];
return anim;
}
EditorSceneFormatImporterCollada::EditorSceneFormatImporterCollada() {
}

View file

@ -40,7 +40,6 @@ public:
virtual uint32_t get_import_flags() const override;
virtual void get_extensions(List<String> *r_extensions) const override;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override;
EditorSceneFormatImporterCollada();
};

View file

@ -457,10 +457,6 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co
return scene;
}
Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
return Ref<Animation>();
}
void EditorOBJImporter::get_extensions(List<String> *r_extensions) const {
r_extensions->push_back("obj");
}

View file

@ -40,7 +40,6 @@ public:
virtual uint32_t get_import_flags() const override;
virtual void get_extensions(List<String> *r_extensions) const override;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override;
EditorOBJImporter();
};

View file

@ -87,26 +87,13 @@ Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_f
ERR_FAIL_V(nullptr);
}
Ref<Animation> EditorSceneFormatImporter::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
Dictionary options_dict;
for (const KeyValue<StringName, Variant> &elem : p_options) {
options_dict[elem.key] = elem.value;
}
Ref<Animation> ret;
if (GDVIRTUAL_CALL(_import_animation, p_path, p_flags, options_dict, p_bake_fps, ret)) {
return ret;
}
ERR_FAIL_V(nullptr);
}
void EditorSceneFormatImporter::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
GDVIRTUAL_CALL(_get_import_options, p_path);
}
Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) {
Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) {
Variant ret;
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_option, ret);
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_for_animation, p_option, ret);
return ret;
}
@ -114,15 +101,15 @@ void EditorSceneFormatImporter::_bind_methods() {
GDVIRTUAL_BIND(_get_import_flags);
GDVIRTUAL_BIND(_get_extensions);
GDVIRTUAL_BIND(_import_scene, "path", "flags", "options", "bake_fps");
GDVIRTUAL_BIND(_import_animation, "path", "flags", "options", "bake_fps");
GDVIRTUAL_BIND(_get_import_options, "path");
GDVIRTUAL_BIND(_get_option_visibility, "path", "option");
GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option");
BIND_CONSTANT(IMPORT_SCENE);
BIND_CONSTANT(IMPORT_ANIMATION);
BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
BIND_CONSTANT(IMPORT_USE_NAMED_SKIN_BINDS);
BIND_CONSTANT(IMPORT_DISCARD_MESHES_AND_MATERIALS);
}
/////////////////////////////////
@ -179,10 +166,10 @@ void EditorScenePostImportPlugin::get_internal_import_options(InternalImportCate
GDVIRTUAL_CALL(_get_internal_import_options, p_category);
current_option_list = nullptr;
}
Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const {
Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const {
current_options = &p_options;
Variant ret;
GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_option, ret);
GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_for_animation, p_option, ret);
current_options = nullptr;
return ret;
}
@ -205,10 +192,10 @@ void EditorScenePostImportPlugin::get_import_options(const String &p_path, List<
GDVIRTUAL_CALL(_get_import_options, p_path);
current_option_list = nullptr;
}
Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const {
Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const {
current_options = &p_options;
Variant ret;
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_option, ret);
GDVIRTUAL_CALL(_get_option_visibility, p_path, p_for_animation, p_option, ret);
current_options = nullptr;
return ret;
}
@ -231,11 +218,11 @@ void EditorScenePostImportPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_import_option_advanced", "type", "name", "default_value", "hint", "hint_string", "usage_flags"), &EditorScenePostImportPlugin::add_import_option_advanced, DEFVAL(PROPERTY_HINT_NONE), DEFVAL(""), DEFVAL(PROPERTY_USAGE_DEFAULT));
GDVIRTUAL_BIND(_get_internal_import_options, "category");
GDVIRTUAL_BIND(_get_internal_option_visibility, "category", "option");
GDVIRTUAL_BIND(_get_internal_option_visibility, "category", "for_animation", "option");
GDVIRTUAL_BIND(_get_internal_option_update_view_required, "category", "option");
GDVIRTUAL_BIND(_internal_process, "category", "base_node", "node", "resource");
GDVIRTUAL_BIND(_get_import_options, "path");
GDVIRTUAL_BIND(_get_option_visibility, "path", "option");
GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option");
GDVIRTUAL_BIND(_pre_process, "scene");
GDVIRTUAL_BIND(_post_process, "scene");
@ -251,11 +238,11 @@ void EditorScenePostImportPlugin::_bind_methods() {
/////////////////////////////////////////////////////////
String ResourceImporterScene::get_importer_name() const {
return "scene";
return animation_importer ? "animation_library" : "scene";
}
String ResourceImporterScene::get_visible_name() const {
return "Scene";
return animation_importer ? "Animation Library" : "Scene";
}
void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const {
@ -265,11 +252,11 @@ void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions
}
String ResourceImporterScene::get_save_extension() const {
return "scn";
return animation_importer ? "res" : "scn";
}
String ResourceImporterScene::get_resource_type() const {
return "PackedScene";
return animation_importer ? "AnimationLibrary" : "PackedScene";
}
int ResourceImporterScene::get_format_version() const {
@ -277,26 +264,34 @@ int ResourceImporterScene::get_format_version() const {
}
bool ResourceImporterScene::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const {
if (p_option.begins_with("animation/")) {
if (animation_importer) {
if (p_option == "animation/import") { // Option ignored, animation always imported.
return false;
}
} else if (p_option.begins_with("animation/")) {
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
return false;
}
}
if (animation_importer && (p_option.begins_with("nodes/") || p_option.begins_with("meshes/") || p_option.begins_with("skins/"))) {
return false; // Nothing to do here for animations.
}
if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) != 2) {
// Only display the lightmap texel size import option when using the Static Lightmaps light baking mode.
return false;
}
for (int i = 0; i < post_importer_plugins.size(); i++) {
Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, p_option, p_options);
Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, animation_importer, p_option, p_options);
if (ret.get_type() == Variant::BOOL) {
return ret;
}
}
for (Ref<EditorSceneFormatImporter> importer : importers) {
Variant ret = importer->get_option_visibility(p_path, p_option, p_options);
Variant ret = importer->get_option_visibility(p_path, animation_importer, p_option, p_options);
if (ret.get_type() == Variant::BOOL) {
return ret;
}
@ -1482,7 +1477,7 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
}
for (int i = 0; i < post_importer_plugins.size(); i++) {
Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), p_option, p_options);
Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), animation_importer, p_option, p_options);
if (ret.get_type() == Variant::BOOL) {
return ret;
}
@ -1974,8 +1969,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
int import_flags = 0;
if (bool(p_options["animation/import"])) {
if (animation_importer) {
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
import_flags |= EditorSceneFormatImporter::IMPORT_DISCARD_MESHES_AND_MATERIALS;
} else {
if (bool(p_options["animation/import"])) {
import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION;
}
}
if (bool(p_options["skins/use_named_skins"])) {
@ -2139,11 +2139,35 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
progress.step(TTR("Saving..."), 104);
Ref<PackedScene> packer = memnew(PackedScene);
packer->pack(scene);
print_verbose("Saving scene to: " + p_save_path + ".scn");
err = ResourceSaver::save(p_save_path + ".scn", packer); //do not take over, let the changed files reload themselves
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'.");
if (animation_importer) {
Ref<AnimationLibrary> library;
for (int i = 0; i < scene->get_child_count(); i++) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i));
if (ap) {
List<StringName> libs;
ap->get_animation_library_list(&libs);
if (libs.size()) {
library = ap->get_animation_library(libs.front()->get());
break;
}
}
}
if (!library.is_valid()) {
library.instantiate(); // Will be empty
}
print_verbose("Saving animation to: " + p_save_path + ".scn");
err = ResourceSaver::save(p_save_path + ".res", library); //do not take over, let the changed files reload themselves
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save animation to file '" + p_save_path + ".res'.");
} else {
Ref<PackedScene> packer = memnew(PackedScene);
packer->pack(scene);
print_verbose("Saving scene to: " + p_save_path + ".scn");
err = ResourceSaver::save(p_save_path + ".scn", packer); //do not take over, let the changed files reload themselves
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'.");
}
memdelete(scene);
@ -2153,17 +2177,26 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
return OK;
}
ResourceImporterScene *ResourceImporterScene::singleton = nullptr;
ResourceImporterScene *ResourceImporterScene::scene_singleton = nullptr;
ResourceImporterScene *ResourceImporterScene::animation_singleton = nullptr;
Vector<Ref<EditorSceneFormatImporter>> ResourceImporterScene::importers;
Vector<Ref<EditorScenePostImportPlugin>> ResourceImporterScene::post_importer_plugins;
bool ResourceImporterScene::ResourceImporterScene::has_advanced_options() const {
return true;
}
void ResourceImporterScene::ResourceImporterScene::show_advanced_options(const String &p_path) {
SceneImportSettings::get_singleton()->open_settings(p_path);
SceneImportSettings::get_singleton()->open_settings(p_path, animation_importer);
}
ResourceImporterScene::ResourceImporterScene() {
singleton = this;
ResourceImporterScene::ResourceImporterScene(bool p_animation_import) {
if (p_animation_import) {
animation_singleton = this;
} else {
scene_singleton = this;
}
animation_importer = p_animation_import;
}
void ResourceImporterScene::add_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority) {
@ -2192,6 +2225,11 @@ void ResourceImporterScene::remove_importer(Ref<EditorSceneFormatImporter> p_imp
importers.erase(p_importer);
}
void ResourceImporterScene::clean_up_importer_plugins() {
importers.clear();
post_importer_plugins.clear();
}
///////////////////////////////////////
uint32_t EditorSceneFormatImporterESCN::get_import_flags() const {
@ -2212,7 +2250,3 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
return scene;
}
Ref<Animation> EditorSceneFormatImporterESCN::import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
ERR_FAIL_V(Ref<Animation>());
}

View file

@ -56,9 +56,8 @@ protected:
GDVIRTUAL0RC(int, _get_import_flags)
GDVIRTUAL0RC(Vector<String>, _get_extensions)
GDVIRTUAL4R(Object *, _import_scene, String, uint32_t, Dictionary, uint32_t)
GDVIRTUAL4R(Ref<Animation>, _import_animation, String, uint32_t, Dictionary, uint32_t)
GDVIRTUAL1(_get_import_options, String)
GDVIRTUAL2RC(Variant, _get_option_visibility, String, String)
GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String)
public:
enum ImportFlags {
@ -67,14 +66,14 @@ public:
IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4,
IMPORT_GENERATE_TANGENT_ARRAYS = 8,
IMPORT_USE_NAMED_SKIN_BINDS = 16,
IMPORT_DISCARD_MESHES_AND_MATERIALS = 32, //used for optimizing animation import
};
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr);
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps);
virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options);
virtual Variant get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options);
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options);
EditorSceneFormatImporter() {}
};
@ -118,11 +117,11 @@ private:
protected:
GDVIRTUAL1(_get_internal_import_options, int)
GDVIRTUAL2RC(Variant, _get_internal_option_visibility, int, String)
GDVIRTUAL3RC(Variant, _get_internal_option_visibility, int, bool, String)
GDVIRTUAL2RC(Variant, _get_internal_option_update_view_required, int, String)
GDVIRTUAL4(_internal_process, int, Node *, Node *, RES)
GDVIRTUAL1(_get_import_options, String)
GDVIRTUAL2RC(Variant, _get_option_visibility, String, String)
GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String)
GDVIRTUAL1(_pre_process, Node *)
GDVIRTUAL1(_post_process, Node *)
@ -134,13 +133,13 @@ public:
void add_import_option_advanced(Variant::Type p_type, const String &p_name, Variant p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT);
virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options);
virtual Variant get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual Variant get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual Variant get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, RES p_resource, const Dictionary &p_options);
virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options);
virtual Variant get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual void pre_process(Node *p_scene, const Map<StringName, Variant> &p_options);
virtual void post_process(Node *p_scene, const Map<StringName, Variant> &p_options);
@ -153,9 +152,11 @@ VARIANT_ENUM_CAST(EditorScenePostImportPlugin::InternalImportCategory)
class ResourceImporterScene : public ResourceImporter {
GDCLASS(ResourceImporterScene, ResourceImporter);
Vector<Ref<EditorSceneFormatImporter>> importers;
static Vector<Ref<EditorSceneFormatImporter>> importers;
static Vector<Ref<EditorScenePostImportPlugin>> post_importer_plugins;
static ResourceImporterScene *singleton;
static ResourceImporterScene *scene_singleton;
static ResourceImporterScene *animation_singleton;
enum LightBakeMode {
LIGHT_BAKE_DISABLED,
@ -225,18 +226,21 @@ class ResourceImporterScene : public ResourceImporter {
void _optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions);
mutable Vector<Ref<EditorScenePostImportPlugin>> post_importer_plugins;
bool animation_importer = false;
public:
static ResourceImporterScene *get_singleton() { return singleton; }
static ResourceImporterScene *get_scene_singleton() { return scene_singleton; }
static ResourceImporterScene *get_animation_singleton() { return animation_singleton; }
void add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority = false);
void remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin);
static void add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority = false);
static void remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin);
const Vector<Ref<EditorSceneFormatImporter>> &get_importers() const { return importers; }
void add_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority = false);
void remove_importer(Ref<EditorSceneFormatImporter> p_importer);
static void add_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority = false);
static void remove_importer(Ref<EditorSceneFormatImporter> p_importer);
static void clean_up_importer_plugins();
virtual String get_importer_name() const override;
virtual String get_visible_name() const override;
@ -283,7 +287,7 @@ public:
virtual bool can_import_threaded() const override { return false; }
ResourceImporterScene();
ResourceImporterScene(bool p_animation_import = false);
template <class M>
static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options);
@ -299,7 +303,6 @@ public:
virtual uint32_t get_import_flags() const override;
virtual void get_extensions(List<String> *r_extensions) const override;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override;
};
#include "scene/resources/box_shape_3d.h"

View file

@ -47,6 +47,8 @@ class SceneImportSettingsData : public Object {
Map<StringName, Variant> current;
Map<StringName, Variant> defaults;
List<ResourceImporter::ImportOption> options;
bool hide_options = false;
String path;
ResourceImporterScene::InternalImportCategory category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX;
@ -60,8 +62,26 @@ class SceneImportSettingsData : public Object {
current[p_name] = p_value;
if (ResourceImporterScene::get_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
SceneImportSettings::get_singleton()->update_view();
if (SceneImportSettings::get_singleton()->is_editing_animation()) {
if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, p_name, current)) {
SceneImportSettings::get_singleton()->update_view();
}
} else {
if (ResourceImporterScene::get_animation_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
SceneImportSettings::get_singleton()->update_view();
}
}
} else {
if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, p_name, current)) {
SceneImportSettings::get_singleton()->update_view();
}
} else {
if (ResourceImporterScene::get_scene_singleton()->get_internal_option_update_view_required(category, p_name, current)) {
SceneImportSettings::get_singleton()->update_view();
}
}
}
return true;
@ -82,9 +102,30 @@ class SceneImportSettingsData : public Object {
return false;
}
void _get_property_list(List<PropertyInfo> *p_list) const {
if (hide_options) {
return;
}
for (const ResourceImporter::ImportOption &E : options) {
if (ResourceImporterScene::get_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
p_list->push_back(E.option);
if (SceneImportSettings::get_singleton()->is_editing_animation()) {
if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, E.option.name, current)) {
p_list->push_back(E.option);
}
} else {
if (ResourceImporterScene::get_animation_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
p_list->push_back(E.option);
}
}
} else {
if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, E.option.name, current)) {
p_list->push_back(E.option);
}
} else {
if (ResourceImporterScene::get_scene_singleton()->get_internal_option_visibility(category, E.option.name, current)) {
p_list->push_back(E.option);
}
}
}
}
}
@ -326,7 +367,9 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
}
MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node);
if (mesh_node && mesh_node->get_mesh().is_valid()) {
_fill_mesh(scene_tree, mesh_node->get_mesh(), item);
if (!editing_animation) {
_fill_mesh(scene_tree, mesh_node->get_mesh(), item);
}
// Add the collider view.
MeshInstance3D *collider_view = memnew(MeshInstance3D);
@ -365,6 +408,9 @@ void SceneImportSettings::_update_scene() {
}
void SceneImportSettings::_update_view_gizmos() {
if (!is_visible()) {
return;
}
for (const KeyValue<String, NodeData> &e : node_map) {
bool generate_collider = false;
if (e.value.settings.has(SNAME("generate/physics"))) {
@ -378,6 +424,7 @@ void SceneImportSettings::_update_view_gizmos() {
}
TypedArray<Node> descendants = mesh_node->find_nodes("collider_view", "MeshInstance3D");
CRASH_COND_MSG(descendants.is_empty(), "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`.");
MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(descendants[0].operator Object *());
@ -460,7 +507,11 @@ void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Var
if (d.has(p_import_id)) {
d = d[p_import_id];
List<ResourceImporterScene::ImportOption> options;
ResourceImporterScene::get_singleton()->get_internal_import_options(p_category, &options);
if (editing_animation) {
ResourceImporterScene::get_animation_singleton()->get_internal_import_options(p_category, &options);
} else {
ResourceImporterScene::get_scene_singleton()->get_internal_import_options(p_category, &options);
}
for (const ResourceImporterScene::ImportOption &E : options) {
String key = E.option.name;
if (d.has(key)) {
@ -472,21 +523,32 @@ void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Var
}
void SceneImportSettings::update_view() {
_update_view_gizmos();
update_view_timer->start();
}
void SceneImportSettings::open_settings(const String &p_path) {
void SceneImportSettings::open_settings(const String &p_path, bool p_for_animation) {
if (scene) {
memdelete(scene);
scene = nullptr;
}
editing_animation = p_for_animation;
scene_import_settings_data->settings = nullptr;
scene = ResourceImporterScene::get_singleton()->pre_import(p_path);
scene_import_settings_data->path = p_path;
scene = ResourceImporterScene::get_scene_singleton()->pre_import(p_path); // Use the scene singleton here because we want to see the full thing.
if (scene == nullptr) {
EditorNode::get_singleton()->show_warning(TTR("Error opening scene"));
return;
}
// Visibility
data_mode->set_tab_hidden(1, p_for_animation);
data_mode->set_tab_hidden(2, p_for_animation);
action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_EXTRACT_MATERIALS), p_for_animation);
action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_CHOOSE_MESH_SAVE_PATHS), p_for_animation);
base_path = p_path;
material_set.clear();
@ -540,7 +602,11 @@ void SceneImportSettings::open_settings(const String &p_path) {
_update_view_gizmos();
_update_camera();
set_title(vformat(TTR("Advanced Import Settings for '%s'"), base_path.get_file()));
if (p_for_animation) {
set_title(vformat(TTR("Advanced Import Settings for AnimationLibrary '%s'"), base_path.get_file()));
} else {
set_title(vformat(TTR("Advanced Import Settings for Scene '%s'"), base_path.get_file()));
}
}
SceneImportSettings *SceneImportSettings::singleton = nullptr;
@ -551,6 +617,7 @@ SceneImportSettings *SceneImportSettings::get_singleton() {
void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
selecting = true;
scene_import_settings_data->hide_options = false;
if (p_type == "Node") {
node_selected->hide(); //always hide just in case
@ -585,10 +652,12 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
scene_import_settings_data->settings = &nd.settings;
if (mi) {
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
scene_import_settings_data->hide_options = editing_animation;
} else if (Object::cast_to<AnimationPlayer>(nd.node)) {
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
} else {
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
scene_import_settings_data->hide_options = editing_animation;
}
}
} else if (p_type == "Animation") {
@ -671,24 +740,36 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
List<ResourceImporter::ImportOption> options;
if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
ResourceImporterScene::get_singleton()->get_import_options(base_path, &options);
if (editing_animation) {
if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
ResourceImporterScene::get_animation_singleton()->get_import_options(base_path, &options);
} else {
ResourceImporterScene::get_animation_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
}
} else {
ResourceImporterScene::get_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) {
ResourceImporterScene::get_scene_singleton()->get_import_options(base_path, &options);
} else {
ResourceImporterScene::get_scene_singleton()->get_internal_import_options(scene_import_settings_data->category, &options);
}
}
scene_import_settings_data->defaults.clear();
scene_import_settings_data->current.clear();
for (const ResourceImporter::ImportOption &E : options) {
scene_import_settings_data->defaults[E.option.name] = E.default_value;
//needed for visibility toggling (fails if something is missing)
if (scene_import_settings_data->settings->has(E.option.name)) {
scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name];
} else {
scene_import_settings_data->current[E.option.name] = E.default_value;
if (scene_import_settings_data->settings) {
for (const ResourceImporter::ImportOption &E : options) {
scene_import_settings_data->defaults[E.option.name] = E.default_value;
//needed for visibility toggling (fails if something is missing)
if (scene_import_settings_data->settings->has(E.option.name)) {
scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name];
} else {
scene_import_settings_data->current[E.option.name] = E.default_value;
}
}
}
scene_import_settings_data->options = options;
inspector->edit(scene_import_settings_data);
scene_import_settings_data->notify_property_list_changed();
@ -836,7 +917,7 @@ void SceneImportSettings::_re_import() {
main_settings["_subresources"] = subresources;
}
EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, "scene", main_settings);
EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, editing_animation ? "animation_library" : "scene", main_settings);
}
void SceneImportSettings::_notification(int p_what) {
@ -1282,6 +1363,11 @@ SceneImportSettings::SceneImportSettings() {
item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettings::_save_path_changed));
save_path->connect("dir_selected", callable_mp(this, &SceneImportSettings::_save_dir_callback));
update_view_timer = memnew(Timer);
update_view_timer->set_wait_time(0.2);
update_view_timer->connect("timeout", callable_mp(this, &SceneImportSettings::_update_view_gizmos));
add_child(update_view_timer);
}
SceneImportSettings::~SceneImportSettings() {

View file

@ -189,12 +189,17 @@ class SceneImportSettings : public ConfirmationDialog {
void _load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category);
bool editing_animation = false;
Timer *update_view_timer;
protected:
void _notification(int p_what);
public:
bool is_editing_animation() const { return editing_animation; }
void update_view();
void open_settings(const String &p_path);
void open_settings(const String &p_path, bool p_for_animation = false);
static SceneImportSettings *get_singleton();
SceneImportSettings();
~SceneImportSettings();

View file

@ -238,13 +238,12 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
return gltf->generate_scene(state, p_bake_fps);
}
Ref<Animation> EditorSceneFormatImporterBlend::import_animation(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps) {
return Ref<Animation>();
}
Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, const String &p_option,
Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
const Map<StringName, Variant> &p_options) {
if (p_path.get_extension().to_lower() != "blend") {
return true;
}
if (p_option.begins_with("animation/")) {
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
return false;
@ -254,6 +253,9 @@ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_pa
}
void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
if (p_path.get_extension().to_lower() != "blend") {
return;
}
#define ADD_OPTION_BOOL(PATH, VALUE) \
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, SNAME(PATH)), VALUE));
#define ADD_OPTION_ENUM(PATH, ENUM_HINT, VALUE) \

View file

@ -68,11 +68,9 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps) override;
virtual void get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) override;
virtual Variant get_option_visibility(const String &p_path, const String &p_option,
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
const Map<StringName, Variant> &p_options) override;
};

View file

@ -105,12 +105,7 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t
return gltf->generate_scene(state, p_bake_fps);
}
Ref<Animation> EditorSceneFormatImporterFBX::import_animation(const String &p_path,
uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
return Ref<Animation>();
}
Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path,
Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation,
const String &p_option, const Map<StringName, Variant> &p_options) {
return true;
}

View file

@ -47,11 +47,9 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps) override;
virtual void get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) override;
virtual Variant get_option_visibility(const String &p_path, const String &p_option,
virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
const Map<StringName, Variant> &p_options) override;
};

View file

@ -64,9 +64,4 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
return doc->generate_scene(state, p_bake_fps);
}
Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path,
uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
return Ref<Animation>();
}
#endif // TOOLS_ENABLED

View file

@ -47,8 +47,6 @@ public:
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,
const Map<StringName, Variant> &p_options, int p_bake_fps) override;
};
#endif // TOOLS_ENABLED

View file

@ -60,7 +60,7 @@
static void _editor_init() {
Ref<EditorSceneFormatImporterGLTF> import_gltf;
import_gltf.instantiate();
ResourceImporterScene::get_singleton()->add_importer(import_gltf);
ResourceImporterScene::add_importer(import_gltf);
// Blend to glTF importer.
@ -72,7 +72,7 @@ static void _editor_init() {
if (blend_enabled) {
Ref<EditorSceneFormatImporterBlend> importer;
importer.instantiate();
ResourceImporterScene::get_singleton()->add_importer(importer);
ResourceImporterScene::add_importer(importer);
Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
blend_import_query.instantiate();
@ -95,7 +95,7 @@ static void _editor_init() {
} else {
Ref<EditorSceneFormatImporterFBX> importer;
importer.instantiate();
ResourceImporterScene::get_singleton()->add_importer(importer);
ResourceImporterScene::add_importer(importer);
}
}
}