Merge pull request #72628 from lyuma/gltf-reimport-appending

Use reimport_append api for importing embedded gltf images
This commit is contained in:
Rémi Verschelde 2023-02-06 17:48:28 +01:00
commit f5a8c58684
No known key found for this signature in database
GPG Key ID: C3336907360768E1
6 changed files with 68 additions and 78 deletions

View File

@ -232,8 +232,9 @@
<param index="0" name="path" type="String" />
<param index="1" name="custom_options" type="Dictionary" default="{}" />
<param index="2" name="custom_importer" type="String" default="&quot;&quot;" />
<param index="3" name="generator_parameters" type="Variant" default="null" />
<description>
This function can only be called during the [method _import] callback and it allows manually importing resources from it. This is useful when the imported file generates external resources that require importing (as example, images). Custom parameters for the ".import" file can be passed via the [param custom_options]. Additionally, in cases where multiple importers can handle a file, the [param custom_importer] ca be specified to force a specific one. This function performs a resource import and returns immediately with a success or error code.
This function can only be called during the [method _import] callback and it allows manually importing resources from it. This is useful when the imported file generates external resources that require importing (as example, images). Custom parameters for the ".import" file can be passed via the [param custom_options]. Additionally, in cases where multiple importers can handle a file, the [param custom_importer] ca be specified to force a specific one. This function performs a resource import and returns immediately with a success or error code. [param generator_parameters] defines optional extra metadata which will be stored as [code]generator_parameters[/code] in the [code]remap[/code] section of the [code].import[/code] file, for example to store a md5 hash of the source data.
</description>
</method>
</methods>

View File

@ -1900,7 +1900,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
return err;
}
Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<StringName, Variant> *p_custom_options, const String &p_custom_importer) {
Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant *p_generator_parameters) {
EditorFileSystemDirectory *fs = nullptr;
int cpos = -1;
bool found = _find_file(p_file, &fs, cpos);
@ -1908,46 +1908,48 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
//try to obtain existing params
HashMap<StringName, Variant> params;
HashMap<StringName, Variant> params = p_custom_options;
String importer_name; //empty by default though
if (!p_custom_importer.is_empty()) {
importer_name = p_custom_importer;
}
if (p_custom_options != nullptr) {
params = *p_custom_options;
}
ResourceUID::ID uid = ResourceUID::INVALID_ID;
Variant gen_params;
Variant generator_parameters;
if (p_generator_parameters) {
generator_parameters = *p_generator_parameters;
}
if (FileAccess::exists(p_file + ".import")) {
//use existing
if (p_custom_options == nullptr) {
Ref<ConfigFile> cf;
cf.instantiate();
Error err = cf->load(p_file + ".import");
if (err == OK) {
if (cf->has_section("params")) {
List<String> sk;
cf->get_section_keys("params", &sk);
for (const String &E : sk) {
Ref<ConfigFile> cf;
cf.instantiate();
Error err = cf->load(p_file + ".import");
if (err == OK) {
if (cf->has_section("params")) {
List<String> sk;
cf->get_section_keys("params", &sk);
for (const String &E : sk) {
if (!params.has(E)) {
params[E] = cf->get_value("params", E);
}
}
}
if (cf->has_section("remap")) {
if (p_custom_importer.is_empty()) {
importer_name = cf->get_value("remap", "importer");
}
if (cf->has_section("remap")) {
if (p_custom_importer.is_empty()) {
importer_name = cf->get_value("remap", "importer");
}
if (cf->has_section_key("remap", "uid")) {
String uidt = cf->get_value("remap", "uid");
uid = ResourceUID::get_singleton()->text_to_id(uidt);
}
if (cf->has_section_key("remap", "uid")) {
String uidt = cf->get_value("remap", "uid");
uid = ResourceUID::get_singleton()->text_to_id(uidt);
}
if (cf->has_section_key("remap", "gen_params")) {
gen_params = cf->get_value("remap", "gen_params");
if (!p_generator_parameters) {
if (cf->has_section_key("remap", "generator_parameters")) {
generator_parameters = cf->get_value("remap", "generator_parameters");
}
}
}
@ -2061,8 +2063,8 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap<Strin
f->store_line("metadata=" + meta.get_construct_string());
}
if (gen_params != Variant()) {
f->store_line("gen_params=" + gen_params.get_construct_string());
if (generator_parameters != Variant()) {
f->store_line("generator_parameters=" + generator_parameters.get_construct_string());
}
f->store_line("");
@ -2164,7 +2166,7 @@ void EditorFileSystem::_find_group_files(EditorFileSystemDirectory *efd, HashMap
}
void EditorFileSystem::reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params) {
_reimport_file(p_file, &p_custom_params, p_importer);
_reimport_file(p_file, p_custom_params, p_importer);
}
void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_import_data) {
@ -2301,9 +2303,9 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
emit_signal(SNAME("resources_reimported"), reloads);
}
Error EditorFileSystem::reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer) {
Error EditorFileSystem::reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) {
ERR_FAIL_COND_V_MSG(!importing, ERR_INVALID_PARAMETER, "Can only append files to import during a current reimport process.");
return _reimport_file(p_file, &p_custom_options, p_custom_importer);
return _reimport_file(p_file, p_custom_options, p_custom_importer, &p_generator_parameters);
}
Error EditorFileSystem::_resource_import(const String &p_path) {

View File

@ -242,7 +242,7 @@ class EditorFileSystem : public Node {
void _update_extensions();
Error _reimport_file(const String &p_file, const HashMap<StringName, Variant> *p_custom_options = nullptr, const String &p_custom_importer = String());
Error _reimport_file(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant *generator_parameters = nullptr);
Error _reimport_group(const String &p_group_file, const Vector<String> &p_files);
bool _test_for_reimport(const String &p_path, bool p_only_imported_files);
@ -315,7 +315,7 @@ public:
EditorFileSystemDirectory *find_file(const String &p_file, int *r_index) const;
void reimport_files(const Vector<String> &p_files);
Error reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer = String());
Error reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters);
void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params);

View File

@ -186,18 +186,18 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa
ERR_FAIL_V_MSG(ERR_METHOD_NOT_FOUND, "Unimplemented _import in add-on.");
}
Error EditorImportPlugin::_append_import_external_resource(const String &p_file, const Dictionary &p_custom_options, const String &p_custom_importer) {
Error EditorImportPlugin::_append_import_external_resource(const String &p_file, const Dictionary &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) {
HashMap<StringName, Variant> options;
List<Variant> keys;
p_custom_options.get_key_list(&keys);
for (const Variant &K : keys) {
options.insert(K, p_custom_options[K]);
}
return append_import_external_resource(p_file, options, p_custom_importer);
return append_import_external_resource(p_file, options, p_custom_importer, p_generator_parameters);
}
Error EditorImportPlugin::append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer) {
return EditorFileSystem::get_singleton()->reimport_append(p_file, p_custom_options, p_custom_importer);
Error EditorImportPlugin::append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) {
return EditorFileSystem::get_singleton()->reimport_append(p_file, p_custom_options, p_custom_importer, p_generator_parameters);
}
void EditorImportPlugin::_bind_methods() {
@ -213,5 +213,5 @@ void EditorImportPlugin::_bind_methods() {
GDVIRTUAL_BIND(_get_import_order)
GDVIRTUAL_BIND(_get_option_visibility, "path", "option_name", "options")
GDVIRTUAL_BIND(_import, "source_file", "save_path", "options", "platform_variants", "gen_files");
ClassDB::bind_method(D_METHOD("append_import_external_resource", "path", "custom_options", "custom_importer"), &EditorImportPlugin::_append_import_external_resource, DEFVAL(Dictionary()), DEFVAL(String()));
ClassDB::bind_method(D_METHOD("append_import_external_resource", "path", "custom_options", "custom_importer", "generator_parameters"), &EditorImportPlugin::_append_import_external_resource, DEFVAL(Dictionary()), DEFVAL(String()), DEFVAL(Variant()));
}

View File

@ -53,7 +53,7 @@ protected:
GDVIRTUAL3RC(bool, _get_option_visibility, String, StringName, Dictionary)
GDVIRTUAL5RC(Error, _import, String, String, Dictionary, TypedArray<String>, TypedArray<String>)
Error _append_import_external_resource(const String &p_file, const Dictionary &p_custom_options = Dictionary(), const String &p_custom_importer = String());
Error _append_import_external_resource(const String &p_file, const Dictionary &p_custom_options = Dictionary(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());
public:
EditorImportPlugin();
@ -69,7 +69,7 @@ public:
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const override;
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata = nullptr) override;
Error append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String());
Error append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());
};
#endif // EDITOR_IMPORT_PLUGIN_H

View File

@ -54,6 +54,9 @@
#include "modules/modules_enabled.gen.h" // For csg, gridmap.
#ifdef TOOLS_ENABLED
#include "editor/editor_file_system.h"
#endif
#ifdef MODULE_CSG_ENABLED
#include "modules/csg/csg_shape.h"
#endif // MODULE_CSG_ENABLED
@ -3232,54 +3235,38 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
p_state->source_images.push_back(Ref<Image>());
} else {
Error err = OK;
bool must_import = false;
bool must_import = true;
Vector<uint8_t> img_data = img->get_data();
Dictionary generator_parameters;
String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + img->get_name() + ".png";
if (!FileAccess::exists(file_path + ".import")) {
if (FileAccess::exists(file_path + ".import")) {
Ref<ConfigFile> config;
config.instantiate();
config->set_value("remap", "importer", "texture");
config->set_value("remap", "type", "Texture2D");
// Currently, it will likely use project defaults of Detect 3D, so textures will be reimported again.
if (!config->has_section_key("params", "mipmaps/generate")) {
config->set_value("params", "mipmaps/generate", true);
config->load(file_path + ".import");
if (config->has_section_key("remap", "generator_parameters")) {
generator_parameters = (Dictionary)config->get_value("remap", "generator_parameters");
}
if (ProjectSettings::get_singleton()->has_setting("importer_defaults/texture")) {
//use defaults if exist
Dictionary importer_defaults = GLOBAL_GET("importer_defaults/texture");
List<Variant> importer_def_keys;
importer_defaults.get_key_list(&importer_def_keys);
for (const Variant &key : importer_def_keys) {
if (!config->has_section_key("params", (String)key)) {
config->set_value("params", (String)key, importer_defaults[key]);
}
}
if (!generator_parameters.has("md5")) {
must_import = false; // Didn't come form a gltf document; don't overwrite.
}
err = config->save(file_path + ".import");
ERR_FAIL_COND_V(err != OK, err);
must_import = true;
}
Vector<uint8_t> png_buffer = img->save_png_to_buffer();
if (ResourceLoader::exists(file_path)) {
Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::READ, &err);
if (err == OK && file.is_valid()) {
Vector<uint8_t> orig_png_buffer = file->get_buffer(file->get_length());
if (png_buffer != orig_png_buffer) {
must_import = true;
}
String existing_md5 = generator_parameters["md5"];
unsigned char md5_hash[16];
CryptoCore::md5(img_data.ptr(), img_data.size(), md5_hash);
String new_md5 = String::hex_encode_buffer(md5_hash, 16);
generator_parameters["md5"] = new_md5;
if (new_md5 == existing_md5) {
must_import = false;
}
} else {
must_import = true;
}
if (must_import) {
Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE, &err);
err = img->save_png(file_path);
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(file.is_null(), FAILED);
file->store_buffer(png_buffer);
file->flush();
file.unref();
// ResourceLoader::import will crash if not is_editor_hint(), so this case is protected above and will fall through to uncompressed.
ResourceLoader::import(file_path);
HashMap<StringName, Variant> custom_options;
custom_options[SNAME("mipmaps/generate")] = true;
// Will only use project settings defaults if custom_importer is empty.
EditorFileSystem::get_singleton()->update_file(file_path);
EditorFileSystem::get_singleton()->reimport_append(file_path, custom_options, String(), generator_parameters);
}
Ref<Texture2D> saved_image = ResourceLoader::load(file_path, "Texture2D");
if (saved_image.is_valid()) {