diff --git a/examples/gl_viewer/gl_viewer.cpp b/examples/gl_viewer/gl_viewer.cpp index 5e70bc8ff..99fc350df 100644 --- a/examples/gl_viewer/gl_viewer.cpp +++ b/examples/gl_viewer/gl_viewer.cpp @@ -377,8 +377,8 @@ bool loadMesh(Viewer* viewer, fastgltf::Mesh& mesh) { auto& material = viewer->asset.materials[it->materialIndex.value()]; if (material.pbrData.baseColorTexture.has_value()) { auto& texture = viewer->asset.textures[material.pbrData.baseColorTexture->textureIndex]; - if (!texture.imageIndex.has_value()) - return false; + if (!texture.imageIndex.has_value()) + return false; primitive.albedoTexture = viewer->textures[texture.imageIndex.value()].texture; } } else { diff --git a/include/fastgltf/types.hpp b/include/fastgltf/types.hpp index 539b5bec7..c9df5f6b3 100644 --- a/include/fastgltf/types.hpp +++ b/include/fastgltf/types.hpp @@ -1610,22 +1610,32 @@ namespace fastgltf { }; struct Texture { - /** - * When empty, an extension or other mechanism SHOULD supply an alternate texture source, - * otherwise behavior is undefined. - */ - Optional imageIndex; + /** + * If no sampler is specified, use a default sampler with repeat wrap and auto filter. + */ + Optional samplerIndex; - /** - * If the imageIndex is specified by the KTX2 or DDS glTF extensions, this is supposed to - * be used as a fallback if those file containers are not supported. - */ - Optional fallbackImageIndex; + /** + * The index of the image used by this texture. Either this will have a value, + * or one of the following extensions will define a texture index. If no extensions + * were enabled while parsing, this will always have a value. + */ + Optional imageIndex; - /** - * If no sampler is specified, use a default sampler with repeat wrap and auto filter. - */ - Optional samplerIndex; + /** + * An optional texture index from the KHR_texture_basisu extension. + */ + Optional basisuImageIndex; + + /** + * An optional texture index from the MSFT_texture_dds extension. + */ + Optional ddsImageIndex; + + /** + * An optional texture index from the EXT_texture_webp extension. + */ + Optional webpImageIndex; std::pmr::string name; }; diff --git a/src/fastgltf.cpp b/src/fastgltf.cpp index 82683201e..0d0d8f922 100644 --- a/src/fastgltf.cpp +++ b/src/fastgltf.cpp @@ -180,7 +180,7 @@ namespace fastgltf { } if (!extensionNotPresent) { - texture.imageIndex = imageIndex; + texture.basisuImageIndex = imageIndex; return true; } } @@ -192,7 +192,7 @@ namespace fastgltf { } if (!extensionNotPresent) { - texture.imageIndex = imageIndex; + texture.ddsImageIndex = imageIndex; return true; } } @@ -204,7 +204,7 @@ namespace fastgltf { } if (!extensionNotPresent) { - texture.imageIndex = imageIndex; + texture.webpImageIndex = imageIndex; return true; } } @@ -1032,9 +1032,21 @@ fg::Error fg::validate(const fastgltf::Asset& asset) { for (const auto& texture : asset.textures) { if (texture.samplerIndex.has_value() && texture.samplerIndex.value() >= asset.samplers.size()) return Error::InvalidGltf; + // imageIndex needs to be defined, unless one of the texture extensions were enabled and define another image index. + if (isExtensionUsed(extensions::KHR_texture_basisu) || isExtensionUsed(extensions::MSFT_texture_dds) || isExtensionUsed(extensions::EXT_texture_webp)) { + if (!texture.imageIndex.has_value() && (!texture.basisuImageIndex.has_value() && !texture.ddsImageIndex.has_value() && !texture.webpImageIndex.has_value())) { + return Error::InvalidGltf; + } + } else if (!texture.imageIndex.has_value()) { + return Error::InvalidGltf; + } if (texture.imageIndex.has_value() && texture.imageIndex.value() >= asset.images.size()) return Error::InvalidGltf; - if (texture.fallbackImageIndex.has_value() && texture.fallbackImageIndex.value() >= asset.images.size()) + if (texture.basisuImageIndex.has_value() && texture.basisuImageIndex.value() >= asset.images.size()) + return Error::InvalidGltf; + if (texture.ddsImageIndex.has_value() && texture.ddsImageIndex.value() >= asset.images.size()) + return Error::InvalidGltf; + if (texture.webpImageIndex.has_value() && texture.webpImageIndex.value() >= asset.images.size()) return Error::InvalidGltf; } @@ -3082,10 +3094,6 @@ fg::Error fg::Parser::parseTextures(simdjson::dom::array& textures, Asset& asset // If we have extensions, we'll use the normal "source" as the fallback and then parse // the extensions for any "source" field. if (hasExtensions) { - if (texture.imageIndex.has_value()) { - // If the source was specified we'll use that as a fallback. - texture.fallbackImageIndex = texture.imageIndex; - } if (!parseTextureExtensions(texture, extensionsObject, config.extensions)) { return Error::InvalidGltf; } diff --git a/tests/extension_tests.cpp b/tests/extension_tests.cpp index 33479e24d..b00c7b710 100644 --- a/tests/extension_tests.cpp +++ b/tests/extension_tests.cpp @@ -25,9 +25,10 @@ TEST_CASE("Loading KHR_texture_basisu glTF files", "[gltf-loader]") { REQUIRE(!asset->images.empty()); auto& texture = asset->textures[1]; - REQUIRE(texture.imageIndex == 1); + REQUIRE(!texture.imageIndex.has_value()); REQUIRE(texture.samplerIndex == 0); - REQUIRE(!texture.fallbackImageIndex.has_value()); + REQUIRE(texture.basisuImageIndex.has_value()); + REQUIRE(texture.basisuImageIndex.value() == 1); auto& image = asset->images.front(); auto* filePath = std::get_if(&image.data);