Skip to content

Commit

Permalink
Change: Move to explicit image indices per extension
Browse files Browse the repository at this point in the history
Instead of the imageIndex and fallbackImageIndex paradigm, fastgltf now provides a normal imageIndex with different image indices for each texture extension. For one, this is done to adjust for easier writing of glTFs and the case where a glTF uses multiple of these extensions.
  • Loading branch information
spnda committed Oct 27, 2023
1 parent 20e4afd commit 83a4154
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 26 deletions.
4 changes: 2 additions & 2 deletions examples/gl_viewer/gl_viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
38 changes: 24 additions & 14 deletions include/fastgltf/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::size_t> imageIndex;
/**
* If no sampler is specified, use a default sampler with repeat wrap and auto filter.
*/
Optional<std::size_t> 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<std::size_t> 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<std::size_t> imageIndex;

/**
* If no sampler is specified, use a default sampler with repeat wrap and auto filter.
*/
Optional<std::size_t> samplerIndex;
/**
* An optional texture index from the KHR_texture_basisu extension.
*/
Optional<std::size_t> basisuImageIndex;

/**
* An optional texture index from the MSFT_texture_dds extension.
*/
Optional<std::size_t> ddsImageIndex;

/**
* An optional texture index from the EXT_texture_webp extension.
*/
Optional<std::size_t> webpImageIndex;

std::pmr::string name;
};
Expand Down
24 changes: 16 additions & 8 deletions src/fastgltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ namespace fastgltf {
}

if (!extensionNotPresent) {
texture.imageIndex = imageIndex;
texture.basisuImageIndex = imageIndex;
return true;
}
}
Expand All @@ -192,7 +192,7 @@ namespace fastgltf {
}

if (!extensionNotPresent) {
texture.imageIndex = imageIndex;
texture.ddsImageIndex = imageIndex;
return true;
}
}
Expand All @@ -204,7 +204,7 @@ namespace fastgltf {
}

if (!extensionNotPresent) {
texture.imageIndex = imageIndex;
texture.webpImageIndex = imageIndex;
return true;
}
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 3 additions & 2 deletions tests/extension_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<fastgltf::sources::URI>(&image.data);
Expand Down

0 comments on commit 83a4154

Please sign in to comment.