Merge pull request #79533 from aaronfranke/gltf-image-keep-bytes
GLTF: Preserve the original bytes when extracting a texture while importing
This commit is contained in:
commit
2e59878201
7 changed files with 44 additions and 10 deletions
|
@ -59,6 +59,12 @@
|
|||
Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_image_file_extension" qualifiers="virtual">
|
||||
<return type="String" />
|
||||
<description>
|
||||
Returns the file extension to use for saving image data into, for example, [code]".png"[/code]. If defined, when this extension is used to handle images, and the images are saved to a separate file, the image bytes will be copied to a file with this extension. If this is set, there should be a [ResourceImporter] class able to import the file. If not defined or empty, Godot will save the image into a PNG file.
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_supported_extensions" qualifiers="virtual">
|
||||
<return type="PackedStringArray" />
|
||||
<description>
|
||||
|
|
|
@ -36,6 +36,7 @@ void GLTFDocumentExtension::_bind_methods() {
|
|||
GDVIRTUAL_BIND(_get_supported_extensions);
|
||||
GDVIRTUAL_BIND(_parse_node_extensions, "state", "gltf_node", "extensions");
|
||||
GDVIRTUAL_BIND(_parse_image_data, "state", "image_data", "mime_type", "ret_image");
|
||||
GDVIRTUAL_BIND(_get_image_file_extension);
|
||||
GDVIRTUAL_BIND(_parse_texture_json, "state", "texture_json", "ret_gltf_texture");
|
||||
GDVIRTUAL_BIND(_generate_scene_node, "state", "gltf_node", "scene_parent");
|
||||
GDVIRTUAL_BIND(_import_post_parse, "state");
|
||||
|
@ -78,6 +79,12 @@ Error GLTFDocumentExtension::parse_image_data(Ref<GLTFState> p_state, const Pack
|
|||
return err;
|
||||
}
|
||||
|
||||
String GLTFDocumentExtension::get_image_file_extension() {
|
||||
String ret;
|
||||
GDVIRTUAL_CALL(_get_image_file_extension, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtension::parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture) {
|
||||
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_NULL_V(r_gltf_texture, ERR_INVALID_PARAMETER);
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
virtual Vector<String> get_supported_extensions();
|
||||
virtual Error parse_node_extensions(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &p_extensions);
|
||||
virtual Error parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image);
|
||||
virtual String get_image_file_extension();
|
||||
virtual Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture);
|
||||
virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
|
||||
virtual Error import_post_parse(Ref<GLTFState> p_state);
|
||||
|
@ -61,6 +62,7 @@ public:
|
|||
GDVIRTUAL0R(Vector<String>, _get_supported_extensions);
|
||||
GDVIRTUAL3R(Error, _parse_node_extensions, Ref<GLTFState>, Ref<GLTFNode>, Dictionary);
|
||||
GDVIRTUAL4R(Error, _parse_image_data, Ref<GLTFState>, PackedByteArray, String, Ref<Image>);
|
||||
GDVIRTUAL0R(String, _get_image_file_extension);
|
||||
GDVIRTUAL3R(Error, _parse_texture_json, Ref<GLTFState>, Dictionary, Ref<GLTFTexture>);
|
||||
GDVIRTUAL3R(Node3D *, _generate_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
|
||||
GDVIRTUAL1R(Error, _import_post_parse, Ref<GLTFState>);
|
||||
|
|
|
@ -51,6 +51,10 @@ Error GLTFDocumentExtensionTextureWebP::parse_image_data(Ref<GLTFState> p_state,
|
|||
return OK;
|
||||
}
|
||||
|
||||
String GLTFDocumentExtensionTextureWebP::get_image_file_extension() {
|
||||
return ".webp";
|
||||
}
|
||||
|
||||
Error GLTFDocumentExtensionTextureWebP::parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture) {
|
||||
if (!p_texture_json.has("extensions")) {
|
||||
return OK;
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
Error import_preflight(Ref<GLTFState> p_state, Vector<String> p_extensions) override;
|
||||
Vector<String> get_supported_extensions() override;
|
||||
Error parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image) override;
|
||||
String get_image_file_extension() override;
|
||||
Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -3064,7 +3064,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state, const String &p_pa
|
|||
return OK;
|
||||
}
|
||||
|
||||
Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index) {
|
||||
Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index, String &r_file_extension) {
|
||||
Ref<Image> r_image;
|
||||
r_image.instantiate();
|
||||
// Check if any GLTFDocumentExtensions want to import this data as an image.
|
||||
|
@ -3073,6 +3073,7 @@ Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, c
|
|||
Error err = ext->parse_image_data(p_state, p_bytes, p_mime_type, r_image);
|
||||
ERR_CONTINUE_MSG(err != OK, "GLTF: Encountered error " + itos(err) + " when parsing image " + itos(p_index) + " in file " + p_state->filename + ". Continuing.");
|
||||
if (!r_image->is_empty()) {
|
||||
r_file_extension = ext->get_image_file_extension();
|
||||
return r_image;
|
||||
}
|
||||
}
|
||||
|
@ -3080,8 +3081,10 @@ Ref<Image> GLTFDocument::_parse_image_bytes_into_image(Ref<GLTFState> p_state, c
|
|||
// First we honor the mime types if they were defined.
|
||||
if (p_mime_type == "image/png") { // Load buffer as PNG.
|
||||
r_image->load_png_from_buffer(p_bytes);
|
||||
r_file_extension = ".png";
|
||||
} else if (p_mime_type == "image/jpeg") { // Loader buffer as JPEG.
|
||||
r_image->load_jpg_from_buffer(p_bytes);
|
||||
r_file_extension = ".jpg";
|
||||
}
|
||||
// If we didn't pass the above tests, we attempt loading as PNG and then JPEG directly.
|
||||
// This covers URIs with base64-encoded data with application/* type but
|
||||
|
@ -3102,7 +3105,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 String &p_mime_type, 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_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>());
|
||||
|
@ -3119,11 +3122,11 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const String
|
|||
p_state->images.push_back(Ref<Texture2D>());
|
||||
p_state->source_images.push_back(Ref<Image>());
|
||||
} else {
|
||||
Error err = OK;
|
||||
bool must_import = true;
|
||||
Vector<uint8_t> img_data = p_image->get_data();
|
||||
Dictionary generator_parameters;
|
||||
String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + p_image->get_name() + ".png";
|
||||
String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + 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();
|
||||
|
@ -3144,8 +3147,18 @@ void GLTFDocument::_parse_image_save_image(Ref<GLTFState> p_state, const String
|
|||
}
|
||||
}
|
||||
if (must_import) {
|
||||
err = p_image->save_png(file_path);
|
||||
ERR_FAIL_COND(err != OK);
|
||||
Error err = OK;
|
||||
if (p_file_extension.is_empty()) {
|
||||
// If a file extension was not specified, save the image data to a PNG file.
|
||||
err = p_image->save_png(file_path);
|
||||
ERR_FAIL_COND(err != OK);
|
||||
} else {
|
||||
// If a file extension was specified, save the original bytes to a file with that extension.
|
||||
Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE, &err);
|
||||
ERR_FAIL_COND(err != OK);
|
||||
file->store_buffer(p_bytes);
|
||||
file->close();
|
||||
}
|
||||
// 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;
|
||||
|
@ -3295,9 +3308,10 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
|
|||
continue;
|
||||
}
|
||||
// Parse the image data from bytes into an Image resource and save if needed.
|
||||
Ref<Image> img = _parse_image_bytes_into_image(p_state, data, mime_type, i);
|
||||
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, mime_type, i, img);
|
||||
_parse_image_save_image(p_state, data, file_extension, i, img);
|
||||
}
|
||||
|
||||
print_verbose("glTF: Total images: " + itos(p_state->images.size()));
|
||||
|
|
|
@ -151,8 +151,8 @@ private:
|
|||
Error _serialize_texture_samplers(Ref<GLTFState> p_state);
|
||||
Error _serialize_images(Ref<GLTFState> p_state, const String &p_path);
|
||||
Error _serialize_lights(Ref<GLTFState> p_state);
|
||||
Ref<Image> _parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index);
|
||||
void _parse_image_save_image(Ref<GLTFState> p_state, const String &p_mime_type, int p_index, Ref<Image> p_image);
|
||||
Ref<Image> _parse_image_bytes_into_image(Ref<GLTFState> p_state, const Vector<uint8_t> &p_bytes, const String &p_mime_type, int p_index, String &r_file_extension);
|
||||
void _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);
|
||||
Error _parse_images(Ref<GLTFState> p_state, const String &p_base_path);
|
||||
Error _parse_textures(Ref<GLTFState> p_state);
|
||||
Error _parse_texture_samplers(Ref<GLTFState> p_state);
|
||||
|
|
Loading…
Reference in a new issue