|
@@ -3932,7 +3932,7 @@ Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, c
|
|
|
return r_image;
|
|
|
}
|
|
|
|
|
|
-void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_file_extension, int p_index, Ref<Image> p_image) {
|
|
|
+void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_resource_uri, const String &p_file_extension, int p_index, Ref<Image> p_image) {
|
|
|
GLTFState::GLTFHandleBinary handling = GLTFState::GLTFHandleBinary(p_state->handle_binary_image);
|
|
|
if (p_image->is_empty() || handling == GLTFState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) {
|
|
|
p_state->images.push_back(Ref<Texture2D>());
|
|
@@ -3950,33 +3950,46 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<
|
|
|
WARN_PRINT(vformat("glTF: Image index '%d' did not have a name. It will be automatically given a name based on its index.", p_index));
|
|
|
p_image->set_name(itos(p_index));
|
|
|
}
|
|
|
- bool must_import = true;
|
|
|
+ bool must_write = true; // If the resource does not exist on the disk within res:// directory write it.
|
|
|
+ bool must_import = true; // Trigger import.
|
|
|
Vector<uint8_t> img_data = p_image->get_data();
|
|
|
Dictionary generator_parameters;
|
|
|
- String file_path = p_state->get_extract_path().path_join(p_state->get_extract_prefix() + "_" + p_image->get_name());
|
|
|
- file_path += p_file_extension.is_empty() ? ".png" : p_file_extension;
|
|
|
- if (FileAccess::exists(file_path + ".import")) {
|
|
|
- Ref<ConfigFile> config;
|
|
|
- config.instantiate();
|
|
|
- config->load(file_path + ".import");
|
|
|
- if (config->has_section_key("remap", "generator_parameters")) {
|
|
|
- generator_parameters = (Dictionary)config->get_value("remap", "generator_parameters");
|
|
|
- }
|
|
|
- if (!generator_parameters.has("md5")) {
|
|
|
- must_import = false; // Didn't come from a gltf document; don't overwrite.
|
|
|
+ String file_path;
|
|
|
+ // If resource_uri is within res:// folder but outside of .godot/imported folder, use it.
|
|
|
+ if (!p_resource_uri.is_empty() && !p_resource_uri.begins_with("res://.godot/imported") && !p_resource_uri.begins_with("res://..")) {
|
|
|
+ file_path = p_resource_uri;
|
|
|
+ must_import = true;
|
|
|
+ must_write = !FileAccess::exists(file_path);
|
|
|
+ } else {
|
|
|
+ // Texture data has to be written to the res:// folder and imported.
|
|
|
+ file_path = p_state->get_extract_path().path_join(p_state->get_extract_prefix() + "_" + p_image->get_name());
|
|
|
+ file_path += p_file_extension.is_empty() ? ".png" : p_file_extension;
|
|
|
+ if (FileAccess::exists(file_path + ".import")) {
|
|
|
+ Ref<ConfigFile> config;
|
|
|
+ config.instantiate();
|
|
|
+ config->load(file_path + ".import");
|
|
|
+ if (config->has_section_key("remap", "generator_parameters")) {
|
|
|
+ generator_parameters = (Dictionary)config->get_value("remap", "generator_parameters");
|
|
|
+ }
|
|
|
+ if (!generator_parameters.has("md5")) {
|
|
|
+ must_write = false; // Didn't come from a gltf document; don't overwrite.
|
|
|
+ must_import = false; // And don't import.
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- if (must_import) {
|
|
|
+
|
|
|
+ if (must_write) {
|
|
|
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_write = false;
|
|
|
must_import = false;
|
|
|
}
|
|
|
}
|
|
|
- if (must_import) {
|
|
|
+ if (must_write) {
|
|
|
Error err = OK;
|
|
|
if (p_file_extension.is_empty()) {
|
|
|
// If a file extension was not specified, save the image data to a PNG file.
|
|
@@ -3989,10 +4002,13 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<
|
|
|
file->store_buffer(p_bytes);
|
|
|
file->close();
|
|
|
}
|
|
|
+ }
|
|
|
+ if (must_import) {
|
|
|
// ResourceLoader::import will crash if not is_editor_hint(), so this case is protected above and will fall through to uncompressed.
|
|
|
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);
|
|
|
}
|
|
@@ -4002,7 +4018,7 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const Vector<
|
|
|
p_state->source_images.push_back(saved_image->get_image());
|
|
|
return;
|
|
|
} else {
|
|
|
- WARN_PRINT(vformat("glTF: Image index '%d' with the name '%s' couldn't be imported. It will be loaded directly instead, uncompressed.", p_index, p_image->get_name()));
|
|
|
+ WARN_PRINT(vformat("glTF: Image index '%d' with the name '%s' resolved to %s couldn't be imported. It will be loaded directly instead, uncompressed.", p_index, p_image->get_name(), file_path));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -4070,6 +4086,9 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
|
|
|
while (used_names.has(image_name)) {
|
|
|
image_name += "_" + itos(i);
|
|
|
}
|
|
|
+
|
|
|
+ String resource_uri;
|
|
|
+
|
|
|
used_names.insert(image_name);
|
|
|
// Load the image data. If we get a byte array, store here for later.
|
|
|
Vector<uint8_t> data;
|
|
@@ -4087,14 +4106,14 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
|
|
|
ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
|
|
|
uri = uri.uri_decode();
|
|
|
uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows.
|
|
|
- // If the image is in the .godot/imported directory, we can't use ResourceLoader.
|
|
|
- if (!p_base_path.begins_with("res://.godot/imported")) {
|
|
|
- // ResourceLoader will rely on the file extension to use the relevant loader.
|
|
|
- // The spec says that if mimeType is defined, it should take precedence (e.g.
|
|
|
- // there could be a `.png` image which is actually JPEG), but there's no easy
|
|
|
- // API for that in Godot, so we'd have to load as a buffer (i.e. embedded in
|
|
|
- // the material), so we only do that only as fallback.
|
|
|
- Ref<Texture2D> texture = ResourceLoader::load(uri, "Texture2D");
|
|
|
+ resource_uri = uri.simplify_path();
|
|
|
+ // ResourceLoader will rely on the file extension to use the relevant loader.
|
|
|
+ // The spec says that if mimeType is defined, it should take precedence (e.g.
|
|
|
+ // there could be a `.png` image which is actually JPEG), but there's no easy
|
|
|
+ // API for that in Godot, so we'd have to load as a buffer (i.e. embedded in
|
|
|
+ // the material), so we only do that only as fallback.
|
|
|
+ if (ResourceLoader::exists(resource_uri)) {
|
|
|
+ Ref<Texture2D> texture = ResourceLoader::load(resource_uri, "Texture2D");
|
|
|
if (texture.is_valid()) {
|
|
|
p_state->images.push_back(texture);
|
|
|
p_state->source_images.push_back(texture->get_image());
|
|
@@ -4105,13 +4124,13 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
|
|
|
// If the mimeType does not match with the file extension, either it should be
|
|
|
// specified in the file, or the GLTFDocumentExtension should handle it.
|
|
|
if (mime_type.is_empty()) {
|
|
|
- mime_type = "image/" + uri.get_extension();
|
|
|
+ mime_type = "image/" + resource_uri.get_extension();
|
|
|
}
|
|
|
// Fallback to loading as byte array. This enables us to support the
|
|
|
// spec's requirement that we honor mimetype regardless of file URI.
|
|
|
- data = FileAccess::get_file_as_bytes(uri);
|
|
|
+ data = FileAccess::get_file_as_bytes(resource_uri);
|
|
|
if (data.size() == 0) {
|
|
|
- WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s because there was no data to load. Skipping it.", i, mime_type, uri));
|
|
|
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded as a buffer of MIME type '%s' from URI: %s because there was no data to load. Skipping it.", i, mime_type, resource_uri));
|
|
|
p_state->images.push_back(Ref<Texture2D>()); // Placeholder to keep count.
|
|
|
p_state->source_images.push_back(Ref<Image>());
|
|
|
continue;
|
|
@@ -4141,7 +4160,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
|
|
|
String file_extension;
|
|
|
Ref<Image> img = _parse_image_bytes_into_image(p_state, data, mime_type, i, file_extension);
|
|
|
img->set_name(image_name);
|
|
|
- _parse_image_save_image(p_state, data, file_extension, i, img);
|
|
|
+ _parse_image_save_image(p_state, data, resource_uri, file_extension, i, img);
|
|
|
}
|
|
|
|
|
|
print_verbose("glTF: Total images: " + itos(p_state->images.size()));
|