summaryrefslogtreecommitdiff
path: root/modules/gltf/gltf_document.cpp
diff options
context:
space:
mode:
authorK. S. Ernest (iFire) Lee <fire@users.noreply.github.com>2022-07-18 17:58:27 -0700
committerLyuma <xn.lyuma@gmail.com>2023-01-27 02:02:02 -0800
commit39922d7167178bab9587aa00a7a108b93db6240e (patch)
tree51e404a83385757d913207cee245a1af6aba8512 /modules/gltf/gltf_document.cpp
parentd1e5903c67956707948b1de370b807e3aad395b7 (diff)
Handle gltf binary
[ Ignore and Warn | Extract Textures (default) | Optimize Loading Embedded as Basisu ] Enable compressed mip maps from Basis Universal for faster compressions. Increase the quality of Basis to avoid corruption. To keep compatibility use the first mip of the previous internal Godot format. Because texture names may have invalid filename characters, adds String::validate_filename to sanitize filenames for import pipeline use.
Diffstat (limited to 'modules/gltf/gltf_document.cpp')
-rw-r--r--modules/gltf/gltf_document.cpp101
1 files changed, 90 insertions, 11 deletions
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index b243ba933d..72c715f0a6 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -33,6 +33,7 @@
#include "extensions/gltf_spec_gloss.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/config_file.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/file_access_memory.h"
@@ -3089,9 +3090,12 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
const uint8_t *data_ptr = nullptr;
int data_size = 0;
+ String image_name;
+
if (d.has("uri")) {
// Handles the first two bullet points from the spec (embedded data, or external file).
String uri = d["uri"];
+ image_name = uri;
if (uri.begins_with("data:")) { // Embedded data using base64.
// Validate data MIME types and throw a warning if it's one we don't know/support.
@@ -3127,6 +3131,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
String extension = uri.get_extension().to_lower();
if (texture.is_valid()) {
p_state->images.push_back(texture);
+ p_state->source_images.push_back(texture->get_image());
continue;
} else if (mimetype == "image/png" || mimetype == "image/jpeg" || extension == "png" || extension == "jpg" || extension == "jpeg") {
// Fallback to loading as byte array.
@@ -3152,6 +3157,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
vformat("glTF: Image index '%d' specifies 'bufferView' but no 'mimeType', which is invalid.", i));
const GLTFBufferViewIndex bvi = d["bufferView"];
+ image_name = itos(bvi);
ERR_FAIL_INDEX_V(bvi, p_state->buffer_views.size(), ERR_PARAMETER_RANGE_ERROR);
@@ -3196,9 +3202,70 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
if (img.is_null()) {
ERR_PRINT(vformat("glTF: Couldn't load image index '%d' with its given mimetype: %s.", i, mimetype));
p_state->images.push_back(Ref<Texture2D>());
+ p_state->source_images.push_back(Ref<Image>());
+ continue;
+ }
+ if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_DISCARD_TEXTURES) {
+ p_state->images.push_back(Ref<Texture2D>());
+ p_state->source_images.push_back(Ref<Image>());
+ continue;
+ } else if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EXTRACT_TEXTURES) {
+ String extracted_image_name = image_name.get_file().get_basename().validate_filename();
+ img->set_name(extracted_image_name);
+ if (p_state->base_path.is_empty()) {
+ p_state->images.push_back(Ref<Texture2D>());
+ p_state->source_images.push_back(Ref<Image>());
+ } else if (img->get_name().is_empty()) {
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be named. Skipping it.", i));
+ p_state->images.push_back(Ref<Texture2D>());
+ p_state->source_images.push_back(Ref<Image>());
+ } else {
+ String file_path = p_state->get_base_path() + "/" + p_state->filename.get_basename() + "_" + img->get_name() + ".png";
+ Ref<ConfigFile> config;
+ config.instantiate();
+ if (FileAccess::exists(file_path + ".import")) {
+ config->load(file_path + ".import");
+ }
+ config->set_value("remap", "importer", "texture");
+ config->set_value("remap", "type", "Texture2D");
+ if (!config->has_section_key("params", "compress/mode")) {
+ config->set_value("remap", "compress/mode", 2); //user may want another compression, so leave it bes
+ }
+ if (!config->has_section_key("params", "mipmaps/generate")) {
+ config->set_value("params", "mipmaps/generate", true);
+ }
+ Error err = OK;
+ err = config->save(file_path + ".import");
+ ERR_FAIL_COND_V(err != OK, err);
+ img->save_png(file_path);
+ ERR_FAIL_COND_V(err != OK, err);
+ ResourceLoader::import(file_path);
+ Ref<Texture2D> saved_image = ResourceLoader::load(file_path, "Texture2D");
+ if (saved_image.is_valid()) {
+ p_state->images.push_back(saved_image);
+ p_state->source_images.push_back(img);
+ } else {
+ WARN_PRINT(vformat("glTF: Image index '%d' couldn't be loaded with the name: %s. Skipping it.", i, img->get_name()));
+ // Placeholder to keep count.
+ p_state->images.push_back(Ref<Texture2D>());
+ p_state->source_images.push_back(Ref<Image>());
+ }
+ }
+ continue;
+ } else if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) {
+ Ref<PortableCompressedTexture2D> tex;
+ tex.instantiate();
+ tex->set_name(img->get_name());
+ tex->set_keep_compressed_buffer(true);
+ p_state->source_images.push_back(img);
+ tex->create_from_image(img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL);
+ p_state->images.push_back(tex);
+ p_state->source_images.push_back(img);
continue;
}
- p_state->images.push_back(ImageTexture::create_from_image(img));
+
+ p_state->images.push_back(Ref<Texture2D>());
+ p_state->source_images.push_back(Ref<Image>());
}
print_verbose("glTF: Total images: " + itos(p_state->images.size()));
@@ -3268,12 +3335,24 @@ GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> p_state, Ref<Texture2
return gltf_texture_i;
}
-Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture) {
+Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> p_state, const GLTFTextureIndex p_texture, int p_texture_types) {
ERR_FAIL_INDEX_V(p_texture, p_state->textures.size(), Ref<Texture2D>());
const GLTFImageIndex image = p_state->textures[p_texture]->get_src_image();
-
ERR_FAIL_INDEX_V(image, p_state->images.size(), Ref<Texture2D>());
-
+ if (GLTFState::GLTFHandleBinary(p_state->handle_binary_image) == GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_BASISU) {
+ Ref<PortableCompressedTexture2D> portable_texture;
+ portable_texture.instantiate();
+ portable_texture->set_keep_compressed_buffer(true);
+ Ref<Image> new_img = p_state->source_images[p_texture]->duplicate();
+ ERR_FAIL_COND_V(new_img.is_null(), Ref<Texture2D>());
+ new_img->generate_mipmaps();
+ if (p_texture_types) {
+ portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, true);
+ } else {
+ portable_texture->create_from_image(new_img, PortableCompressedTexture2D::COMPRESSION_MODE_BASIS_UNIVERSAL, false);
+ }
+ p_state->images.write[image] = portable_texture;
+ }
return p_state->images[image];
}
@@ -3684,7 +3763,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
material->set_texture_filter(diffuse_sampler->get_filter_mode());
material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode());
}
- Ref<Texture2D> diffuse_texture = _get_texture(p_state, diffuse_texture_dict["index"]);
+ Ref<Texture2D> diffuse_texture = _get_texture(p_state, diffuse_texture_dict["index"], TEXTURE_TYPE_GENERIC);
if (diffuse_texture.is_valid()) {
spec_gloss->diffuse_img = diffuse_texture->get_image();
material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture);
@@ -3712,7 +3791,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
if (sgm.has("specularGlossinessTexture")) {
const Dictionary &spec_gloss_texture = sgm["specularGlossinessTexture"];
if (spec_gloss_texture.has("index")) {
- const Ref<Texture2D> orig_texture = _get_texture(p_state, spec_gloss_texture["index"]);
+ const Ref<Texture2D> orig_texture = _get_texture(p_state, spec_gloss_texture["index"], TEXTURE_TYPE_GENERIC);
if (orig_texture.is_valid()) {
spec_gloss->spec_gloss_img = orig_texture->get_image();
}
@@ -3735,7 +3814,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(p_state, bct["index"]);
material->set_texture_filter(bct_sampler->get_filter_mode());
material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode());
- material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(p_state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC));
}
if (!mr.has("baseColorFactor")) {
material->set_albedo(Color(1, 1, 1));
@@ -3758,7 +3837,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
if (mr.has("metallicRoughnessTexture")) {
const Dictionary &bct = mr["metallicRoughnessTexture"];
if (bct.has("index")) {
- const Ref<Texture2D> t = _get_texture(p_state, bct["index"]);
+ const Ref<Texture2D> t = _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC);
material->set_texture(BaseMaterial3D::TEXTURE_METALLIC, t);
material->set_metallic_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_BLUE);
material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, t);
@@ -3776,7 +3855,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
if (d.has("normalTexture")) {
const Dictionary &bct = d["normalTexture"];
if (bct.has("index")) {
- material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_NORMAL, _get_texture(p_state, bct["index"], TEXTURE_TYPE_NORMAL));
material->set_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING, true);
}
if (bct.has("scale")) {
@@ -3786,7 +3865,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
if (d.has("occlusionTexture")) {
const Dictionary &bct = d["occlusionTexture"];
if (bct.has("index")) {
- material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC));
material->set_ao_texture_channel(BaseMaterial3D::TEXTURE_CHANNEL_RED);
material->set_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION, true);
}
@@ -3804,7 +3883,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> p_state) {
if (d.has("emissiveTexture")) {
const Dictionary &bct = d["emissiveTexture"];
if (bct.has("index")) {
- material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index"]));
+ material->set_texture(BaseMaterial3D::TEXTURE_EMISSION, _get_texture(p_state, bct["index"], TEXTURE_TYPE_GENERIC));
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
material->set_emission(Color(0, 0, 0));
}