summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/gltf/llgltfloader.cpp578
1 files changed, 472 insertions, 106 deletions
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 2db803ef3e..52147ad5c3 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -122,10 +122,8 @@ bool LLGLTFLoader::OpenFile(const std::string &filename)
mMeshesLoaded = parseMeshes();
if (mMeshesLoaded) uploadMeshes();
- /*
mMaterialsLoaded = parseMaterials();
if (mMaterialsLoaded) uploadMaterials();
- */
setLoadState(DONE);
@@ -178,7 +176,7 @@ bool LLGLTFLoader::parseMeshes()
mTransform *= rotation;
transformation = mTransform;
-
+
// adjust the transformation to compensate for mesh normalization
LLVector3 mesh_scale_vector;
LLVector3 mesh_translation_vector;
@@ -193,7 +191,7 @@ bool LLGLTFLoader::parseMeshes()
mesh_scale.initScale(mesh_scale_vector);
mesh_scale *= transformation;
transformation = mesh_scale;
-
+
if (transformation.determinant() < 0)
{ // negative scales are not supported
LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: "
@@ -233,7 +231,7 @@ void LLGLTFLoader::populateJointFromSkin(const LL::GLTF::Skin& skin)
mJointsFromNode.push_front(jointNode.mName);
}
}
-
+
bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& mesh, const LL::GLTF::Node& nodeno, material_map& mats)
{
pModel->mLabel = mesh.mName;
@@ -252,22 +250,103 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
// count. Just go ahead and populate faces direct from the GLTF primitives here. -Geenz 2025-04-07
LLVolumeFace face;
LLVolumeFace::VertexMapData::PointMap point_map;
-
+
std::vector<GLTFVertex> vertices;
std::vector<U16> indices;
-
- LLImportMaterial impMat;
-
- LL::GLTF::Material* material = nullptr;
- if (prim.mMaterial >= 0)
- material = &mGLTFAsset.mMaterials[prim.mMaterial];
+ LLImportMaterial impMat;
+ impMat.mDiffuseColor = LLColor4::white; // Default color
- impMat.mDiffuseColor = LLColor4::white;
+ // Process material if available
+ if (prim.mMaterial >= 0 && prim.mMaterial < mGLTFAsset.mMaterials.size())
+ {
+ LL::GLTF::Material* material = &mGLTFAsset.mMaterials[prim.mMaterial];
+
+ // Set diffuse color from base color factor
+ impMat.mDiffuseColor = LLColor4(
+ material->mPbrMetallicRoughness.mBaseColorFactor[0],
+ material->mPbrMetallicRoughness.mBaseColorFactor[1],
+ material->mPbrMetallicRoughness.mBaseColorFactor[2],
+ material->mPbrMetallicRoughness.mBaseColorFactor[3]
+ );
+
+ // Process base color texture if it exists
+ if (material->mPbrMetallicRoughness.mBaseColorTexture.mIndex >= 0)
+ {
+ S32 texIndex = material->mPbrMetallicRoughness.mBaseColorTexture.mIndex;
+ if (texIndex < mGLTFAsset.mTextures.size())
+ {
+ S32 sourceIndex = mGLTFAsset.mTextures[texIndex].mSource;
+ if (sourceIndex >= 0 && sourceIndex < mGLTFAsset.mImages.size())
+ {
+ LL::GLTF::Image& image = mGLTFAsset.mImages[sourceIndex];
+
+ // Use URI as texture file name
+ if (!image.mUri.empty())
+ {
+ // URI might be a remote URL or a local path
+ std::string filename = image.mUri;
+
+ // Extract just the filename from the URI
+ size_t pos = filename.find_last_of("/\\");
+ if (pos != std::string::npos)
+ {
+ filename = filename.substr(pos + 1);
+ }
+
+ // Store the texture filename
+ impMat.mDiffuseMapFilename = filename;
+ impMat.mDiffuseMapLabel = material->mName.empty() ? filename : material->mName;
+
+ LL_INFOS("GLTF_IMPORT") << "Found texture: " << impMat.mDiffuseMapFilename << LL_ENDL;
+
+ // If the image has a texture loaded already, use it
+ if (image.mTexture.notNull())
+ {
+ impMat.setDiffuseMap(image.mTexture->getID());
+ LL_INFOS("GLTF_IMPORT") << "Using existing texture ID: " << image.mTexture->getID().asString() << LL_ENDL;
+ }
+ else
+ {
+ // Let the model preview know we need to load this texture
+ mNumOfFetchingTextures++;
+ LL_INFOS("GLTF_IMPORT") << "Adding texture to load queue: " << impMat.mDiffuseMapFilename << LL_ENDL;
+ }
+ }
+ else if (image.mTexture.notNull())
+ {
+ // No URI but we have a texture, use it directly
+ impMat.setDiffuseMap(image.mTexture->getID());
+ LL_INFOS("GLTF_IMPORT") << "Using existing texture ID without URI: " << image.mTexture->getID().asString() << LL_ENDL;
+ }
+ else if (image.mBufferView >= 0)
+ {
+ // For embedded textures (no URI but has buffer data)
+ // Create a pseudo filename for the embedded texture
+ std::string pseudo_filename = "gltf_embedded_texture_" + std::to_string(sourceIndex) + ".png";
+ impMat.mDiffuseMapFilename = pseudo_filename;
+ impMat.mDiffuseMapLabel = material->mName.empty() ? pseudo_filename : material->mName;
+
+ // Mark for loading
+ mNumOfFetchingTextures++;
+ LL_INFOS("GLTF_IMPORT") << "Adding embedded texture to load queue: " << pseudo_filename << LL_ENDL;
+ }
+ }
+ }
+ }
+ }
for (U32 i = 0; i < prim.getVertexCount(); i++)
{
+ // Apply scaling directly to the vertex positions as they're read from the file
+ const float DIRECT_SCALE = 0.01f; // 1/100th scale
+
GLTFVertex vert;
+ vert.position = glm::vec3(
+ prim.mPositions[i][0] * DIRECT_SCALE,
+ prim.mPositions[i][1] * DIRECT_SCALE,
+ prim.mPositions[i][2] * DIRECT_SCALE
+ );
vert.position = glm::vec3(prim.mPositions[i][0], prim.mPositions[i][1], prim.mPositions[i][2]);
vert.normal = glm::vec3(prim.mNormals[i][0], prim.mNormals[i][1], prim.mNormals[i][2]);
vert.uv0 = glm::vec2(prim.mTexCoords0[i][0],-prim.mTexCoords0[i][1]);
@@ -296,7 +375,6 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
vert.weights = glm::vec4(prim.mWeights[i]);
}
-
vertices.push_back(vert);
}
@@ -313,19 +391,18 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
{
LLVolumeFace::VertexData vert;
- if (vertices[i].position.x > max.x)
+ if (i == 0 || vertices[i].position.x > max.x)
max.x = vertices[i].position.x;
- if (vertices[i].position.y > max.y)
+ if (i == 0 || vertices[i].position.y > max.y)
max.y = vertices[i].position.y;
- if (vertices[i].position.z > max.z)
+ if (i == 0 || vertices[i].position.z > max.z)
max.z = vertices[i].position.z;
-
- if (vertices[i].position.x < min.x)
+ if (i == 0 || vertices[i].position.x < min.x)
min.x = vertices[i].position.x;
- if (vertices[i].position.y < min.y)
+ if (i == 0 || vertices[i].position.y < min.y)
min.y = vertices[i].position.y;
- if (vertices[i].position.z < min.z)
+ if (i == 0 || vertices[i].position.z < min.z)
min.z = vertices[i].position.z;
LLVector4a position = LLVector4a(vertices[i].position.x, vertices[i].position.y, vertices[i].position.z);
@@ -377,8 +454,26 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
face.mExtents[1] = LLVector4a(max.x, max.y, max.z, 0);
pModel->getVolumeFaces().push_back(face);
- pModel->getMaterialList().push_back("mat" + std::to_string(prim.mMaterial));
- mats["mat" + std::to_string(prim.mMaterial)] = impMat;
+
+ // Create a unique material name for this primitive
+ std::string materialName;
+ if (prim.mMaterial >= 0 && prim.mMaterial < mGLTFAsset.mMaterials.size())
+ {
+ LL::GLTF::Material* material = &mGLTFAsset.mMaterials[prim.mMaterial];
+ materialName = material->mName;
+
+ if (materialName.empty())
+ {
+ materialName = "mat" + std::to_string(prim.mMaterial);
+ }
+ }
+ else
+ {
+ materialName = "mat_default" + std::to_string(pModel->getNumVolumeFaces() - 1);
+ }
+
+ pModel->getMaterialList().push_back(materialName);
+ mats[materialName] = impMat;
}
else {
LL_INFOS() << "Unable to process mesh due to 16-bit index limits" << LL_ENDL;
@@ -394,56 +489,70 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
bool LLGLTFLoader::parseMaterials()
{
- return true;
- /*
if (!mGltfLoaded) return false;
// fill local texture data structures
mSamplers.clear();
- for (auto in_sampler : mGltfModel.samplers)
+ for (auto& in_sampler : mGLTFAsset.mSamplers)
{
gltf_sampler sampler;
- sampler.magFilter = in_sampler.magFilter > 0 ? in_sampler.magFilter : GL_LINEAR;
- sampler.minFilter = in_sampler.minFilter > 0 ? in_sampler.minFilter : GL_LINEAR;;
- sampler.wrapS = in_sampler.wrapS;
- sampler.wrapT = in_sampler.wrapT;
- sampler.name = in_sampler.name; // unused
+ sampler.magFilter = in_sampler.mMagFilter > 0 ? in_sampler.mMagFilter : GL_LINEAR;
+ sampler.minFilter = in_sampler.mMinFilter > 0 ? in_sampler.mMinFilter : GL_LINEAR;
+ sampler.wrapS = in_sampler.mWrapS;
+ sampler.wrapT = in_sampler.mWrapT;
+ sampler.name = in_sampler.mName;
mSamplers.push_back(sampler);
}
mImages.clear();
- for (auto in_image : mGltfModel.images)
+ for (auto& in_image : mGLTFAsset.mImages)
{
gltf_image image;
- image.numChannels = in_image.component;
- image.bytesPerChannel = in_image.bits >> 3; // Convert bits to bytes
- image.pixelType = in_image.pixel_type; // Maps exactly, i.e. TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE == GL_UNSIGNED_BYTE, etc
- image.size = static_cast<U32>(in_image.image.size());
- image.height = in_image.height;
- image.width = in_image.width;
- image.data = in_image.image.data();
-
- if (in_image.as_is)
+ image.numChannels = in_image.mComponent;
+ image.bytesPerChannel = in_image.mBits >> 3; // Convert bits to bytes
+ image.pixelType = in_image.mPixelType;
+ image.size = 0; // We'll calculate this below if we have valid dimensions
+
+ // Get dimensions from the texture if available
+ if (in_image.mTexture && in_image.mTexture->getDiscardLevel() >= 0)
{
- LL_WARNS("GLTF_IMPORT") << "Unsupported image encoding" << LL_ENDL;
- return false;
+ image.height = in_image.mTexture->getHeight();
+ image.width = in_image.mTexture->getWidth();
+ // Since we don't have direct access to the raw data, we'll use the dimensions to calculate size
+ if (image.height > 0 && image.width > 0 && image.numChannels > 0 && image.bytesPerChannel > 0)
+ {
+ image.size = static_cast<U32>(image.height * image.width * image.numChannels * image.bytesPerChannel);
+ }
+ }
+ else
+ {
+ // Fallback to provided dimensions
+ image.height = in_image.mHeight;
+ image.width = in_image.mWidth;
+ if (image.height > 0 && image.width > 0 && image.numChannels > 0 && image.bytesPerChannel > 0)
+ {
+ image.size = static_cast<U32>(image.height * image.width * image.numChannels * image.bytesPerChannel);
+ }
}
- if (image.size != image.height * image.width * image.numChannels * image.bytesPerChannel)
+ // If we couldn't determine the size, skip this image
+ if (image.size == 0)
{
- LL_WARNS("GLTF_IMPORT") << "Image size error" << LL_ENDL;
- return false;
+ LL_WARNS("GLTF_IMPORT") << "Image size could not be determined" << LL_ENDL;
+ continue;
}
+ // We don't have direct access to the image data, so data pointer remains nullptr
+ image.data = nullptr;
mImages.push_back(image);
}
mTextures.clear();
- for (auto in_tex : mGltfModel.textures)
+ for (auto& in_tex : mGLTFAsset.mTextures)
{
gltf_texture tex;
- tex.imageIdx = in_tex.source;
- tex.samplerIdx = in_tex.sampler;
+ tex.imageIdx = in_tex.mSource;
+ tex.samplerIdx = in_tex.mSampler;
tex.imageUuid.setNull();
if (tex.imageIdx >= mImages.size() || tex.samplerIdx >= mSamplers.size())
@@ -456,58 +565,96 @@ bool LLGLTFLoader::parseMaterials()
}
// parse each material
- for (tinygltf::Material gltf_material : mGltfModel.materials)
+ mMaterials.clear();
+ for (const auto& gltf_material : mGLTFAsset.mMaterials)
{
gltf_render_material mat;
- mat.name = gltf_material.name;
-
- tinygltf::PbrMetallicRoughness& pbr = gltf_material.pbrMetallicRoughness;
- mat.hasPBR = true; // Always true, for now
-
- mat.baseColor.set(pbr.baseColorFactor.data());
- mat.hasBaseTex = pbr.baseColorTexture.index >= 0;
- mat.baseColorTexIdx = pbr.baseColorTexture.index;
- mat.baseColorTexCoords = pbr.baseColorTexture.texCoord;
-
- mat.metalness = pbr.metallicFactor;
- mat.roughness = pbr.roughnessFactor;
- mat.hasMRTex = pbr.metallicRoughnessTexture.index >= 0;
- mat.metalRoughTexIdx = pbr.metallicRoughnessTexture.index;
- mat.metalRoughTexCoords = pbr.metallicRoughnessTexture.texCoord;
-
- mat.normalScale = gltf_material.normalTexture.scale;
- mat.hasNormalTex = gltf_material.normalTexture.index >= 0;
- mat.normalTexIdx = gltf_material.normalTexture.index;
- mat.normalTexCoords = gltf_material.normalTexture.texCoord;
-
- mat.occlusionScale = gltf_material.occlusionTexture.strength;
- mat.hasOcclusionTex = gltf_material.occlusionTexture.index >= 0;
- mat.occlusionTexIdx = gltf_material.occlusionTexture.index;
- mat.occlusionTexCoords = gltf_material.occlusionTexture.texCoord;
-
- mat.emissiveColor.set(gltf_material.emissiveFactor.data());
- mat.hasEmissiveTex = gltf_material.emissiveTexture.index >= 0;
- mat.emissiveTexIdx = gltf_material.emissiveTexture.index;
- mat.emissiveTexCoords = gltf_material.emissiveTexture.texCoord;
-
- mat.alphaMode = gltf_material.alphaMode;
- mat.alphaMask = gltf_material.alphaCutoff;
-
- if ((mat.hasNormalTex && (mat.normalTexIdx >= mTextures.size())) ||
- (mat.hasOcclusionTex && (mat.occlusionTexIdx >= mTextures.size())) ||
- (mat.hasEmissiveTex && (mat.emissiveTexIdx >= mTextures.size())) ||
- (mat.hasBaseTex && (mat.baseColorTexIdx >= mTextures.size())) ||
- (mat.hasMRTex && (mat.metalRoughTexIdx >= mTextures.size())))
+ mat.name = gltf_material.mName;
+
+ // PBR Metallic Roughness properties
+ mat.hasPBR = true;
+
+ // Base color factor
+ mat.baseColor = LLColor4(
+ gltf_material.mPbrMetallicRoughness.mBaseColorFactor[0],
+ gltf_material.mPbrMetallicRoughness.mBaseColorFactor[1],
+ gltf_material.mPbrMetallicRoughness.mBaseColorFactor[2],
+ gltf_material.mPbrMetallicRoughness.mBaseColorFactor[3]
+ );
+
+ // Base color texture
+ mat.hasBaseTex = gltf_material.mPbrMetallicRoughness.mBaseColorTexture.mIndex >= 0;
+ mat.baseColorTexIdx = gltf_material.mPbrMetallicRoughness.mBaseColorTexture.mIndex;
+ mat.baseColorTexCoords = gltf_material.mPbrMetallicRoughness.mBaseColorTexture.mTexCoord;
+
+ // Metalness and roughness
+ mat.metalness = gltf_material.mPbrMetallicRoughness.mMetallicFactor;
+ mat.roughness = gltf_material.mPbrMetallicRoughness.mRoughnessFactor;
+
+ // Metallic-roughness texture
+ mat.hasMRTex = gltf_material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mIndex >= 0;
+ mat.metalRoughTexIdx = gltf_material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mIndex;
+ mat.metalRoughTexCoords = gltf_material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTexCoord;
+
+ // Normal texture
+ mat.normalScale = gltf_material.mNormalTexture.mScale;
+ mat.hasNormalTex = gltf_material.mNormalTexture.mIndex >= 0;
+ mat.normalTexIdx = gltf_material.mNormalTexture.mIndex;
+ mat.normalTexCoords = gltf_material.mNormalTexture.mTexCoord;
+
+ // Occlusion texture
+ mat.occlusionScale = gltf_material.mOcclusionTexture.mStrength;
+ mat.hasOcclusionTex = gltf_material.mOcclusionTexture.mIndex >= 0;
+ mat.occlusionTexIdx = gltf_material.mOcclusionTexture.mIndex;
+ mat.occlusionTexCoords = gltf_material.mOcclusionTexture.mTexCoord;
+
+ // Emissive texture and color
+ mat.emissiveColor = LLColor4(
+ gltf_material.mEmissiveFactor[0],
+ gltf_material.mEmissiveFactor[1],
+ gltf_material.mEmissiveFactor[2],
+ 1.0f
+ );
+ mat.hasEmissiveTex = gltf_material.mEmissiveTexture.mIndex >= 0;
+ mat.emissiveTexIdx = gltf_material.mEmissiveTexture.mIndex;
+ mat.emissiveTexCoords = gltf_material.mEmissiveTexture.mTexCoord;
+
+ // Convert AlphaMode enum to string
+ switch (gltf_material.mAlphaMode)
+ {
+ case LL::GLTF::Material::AlphaMode::OPAQUE:
+ mat.alphaMode = "OPAQUE";
+ break;
+ case LL::GLTF::Material::AlphaMode::MASK:
+ mat.alphaMode = "MASK";
+ break;
+ case LL::GLTF::Material::AlphaMode::BLEND:
+ mat.alphaMode = "BLEND";
+ break;
+ default:
+ mat.alphaMode = "OPAQUE";
+ break;
+ }
+
+ mat.alphaMask = gltf_material.mAlphaCutoff;
+
+ // Verify that all referenced textures are valid
+ if ((mat.hasNormalTex && (mat.normalTexIdx >= mTextures.size())) ||
+ (mat.hasOcclusionTex && (mat.occlusionTexIdx >= mTextures.size())) ||
+ (mat.hasEmissiveTex && (mat.emissiveTexIdx >= mTextures.size())) ||
+ (mat.hasBaseTex && (mat.baseColorTexIdx >= mTextures.size())) ||
+ (mat.hasMRTex && (mat.metalRoughTexIdx >= mTextures.size())))
{
LL_WARNS("GLTF_IMPORT") << "Texture resource index error" << LL_ENDL;
return false;
}
- if ((mat.hasNormalTex && (mat.normalTexCoords > 2)) || // mesh can have up to 3 sets of UV
- (mat.hasOcclusionTex && (mat.occlusionTexCoords > 2)) ||
- (mat.hasEmissiveTex && (mat.emissiveTexCoords > 2)) ||
- (mat.hasBaseTex && (mat.baseColorTexCoords > 2)) ||
- (mat.hasMRTex && (mat.metalRoughTexCoords > 2)))
+ // Verify texture coordinate sets are valid (mesh can have up to 3 sets of UV)
+ if ((mat.hasNormalTex && (mat.normalTexCoords > 2)) ||
+ (mat.hasOcclusionTex && (mat.occlusionTexCoords > 2)) ||
+ (mat.hasEmissiveTex && (mat.emissiveTexCoords > 2)) ||
+ (mat.hasBaseTex && (mat.baseColorTexCoords > 2)) ||
+ (mat.hasMRTex && (mat.metalRoughTexCoords > 2)))
{
LL_WARNS("GLTF_IMPORT") << "Image texcoord index error" << LL_ENDL;
return false;
@@ -517,7 +664,6 @@ bool LLGLTFLoader::parseMaterials()
}
return true;
- */
}
// TODO: convert raw vertex buffers to UUIDs
@@ -529,18 +675,34 @@ void LLGLTFLoader::uploadMeshes()
// convert raw image buffers to texture UUIDs & assemble into a render material
void LLGLTFLoader::uploadMaterials()
{
- for (gltf_render_material mat : mMaterials) // Initially 1 material per gltf file, but design for multiple
+ LL_INFOS("GLTF_IMPORT") << "Uploading materials, count: " << mMaterials.size() << LL_ENDL;
+
+ for (gltf_render_material& mat : mMaterials)
{
- if (mat.hasBaseTex)
+ LL_INFOS("GLTF_IMPORT") << "Processing material: " << mat.name << LL_ENDL;
+
+ // Process base color texture
+ if (mat.hasBaseTex && mat.baseColorTexIdx < mTextures.size())
{
gltf_texture& gtex = mTextures[mat.baseColorTexIdx];
if (gtex.imageUuid.isNull())
{
+ LL_INFOS("GLTF_IMPORT") << "Loading base color texture for material " << mat.name << LL_ENDL;
gtex.imageUuid = imageBufferToTextureUUID(gtex);
+
+ if (gtex.imageUuid.notNull())
+ {
+ LL_INFOS("GLTF_IMPORT") << "Base color texture loaded, ID: " << gtex.imageUuid.asString() << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("GLTF_IMPORT") << "Failed to load base color texture for material " << mat.name << LL_ENDL;
+ }
}
}
- if (mat.hasMRTex)
+ // Process other textures similarly
+ if (mat.hasMRTex && mat.metalRoughTexIdx < mTextures.size())
{
gltf_texture& gtex = mTextures[mat.metalRoughTexIdx];
if (gtex.imageUuid.isNull())
@@ -549,7 +711,7 @@ void LLGLTFLoader::uploadMaterials()
}
}
- if (mat.hasNormalTex)
+ if (mat.hasNormalTex && mat.normalTexIdx < mTextures.size())
{
gltf_texture& gtex = mTextures[mat.normalTexIdx];
if (gtex.imageUuid.isNull())
@@ -558,7 +720,7 @@ void LLGLTFLoader::uploadMaterials()
}
}
- if (mat.hasOcclusionTex)
+ if (mat.hasOcclusionTex && mat.occlusionTexIdx < mTextures.size())
{
gltf_texture& gtex = mTextures[mat.occlusionTexIdx];
if (gtex.imageUuid.isNull())
@@ -567,7 +729,7 @@ void LLGLTFLoader::uploadMaterials()
}
}
- if (mat.hasEmissiveTex)
+ if (mat.hasEmissiveTex && mat.emissiveTexIdx < mTextures.size())
{
gltf_texture& gtex = mTextures[mat.emissiveTexIdx];
if (gtex.imageUuid.isNull())
@@ -576,18 +738,222 @@ void LLGLTFLoader::uploadMaterials()
}
}
}
+
+ // Update material map for all model instances to ensure textures are properly associated
+ // mScene is a std::map<LLMatrix4, model_instance_list>, not an array, so we need to iterate through it correctly
+ for (auto& scene_entry : mScene)
+ {
+ for (LLModelInstance& instance : scene_entry.second)
+ {
+ LLModel* model = instance.mModel;
+
+ if (model)
+ {
+ for (size_t i = 0; i < model->getMaterialList().size(); ++i)
+ {
+ const std::string& matName = model->getMaterialList()[i];
+ if (!matName.empty())
+ {
+ // Ensure this material exists in the instance's material map
+ if (instance.mMaterial.find(matName) == instance.mMaterial.end())
+ {
+ // Find material in our render materials
+ for (const auto& renderMat : mMaterials)
+ {
+ if (renderMat.name == matName)
+ {
+ // Create an import material from the render material
+ LLImportMaterial impMat;
+ impMat.mDiffuseColor = renderMat.baseColor;
+
+ // Set diffuse texture if available
+ if (renderMat.hasBaseTex && renderMat.baseColorTexIdx < mTextures.size())
+ {
+ const gltf_texture& gtex = mTextures[renderMat.baseColorTexIdx];
+ if (!gtex.imageUuid.isNull())
+ {
+ impMat.setDiffuseMap(gtex.imageUuid);
+ LL_INFOS("GLTF_IMPORT") << "Setting texture " << gtex.imageUuid.asString() << " for material " << matName << LL_ENDL;
+ }
+ }
+
+ // Add material to instance's material map
+ instance.mMaterial[matName] = impMat;
+ LL_INFOS("GLTF_IMPORT") << "Added material " << matName << " to instance" << LL_ENDL;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
LLUUID LLGLTFLoader::imageBufferToTextureUUID(const gltf_texture& tex)
{
- //gltf_image& image = mImages[tex.imageIdx];
- //gltf_sampler& sampler = mSamplers[tex.samplerIdx];
+ if (tex.imageIdx >= mImages.size() || tex.samplerIdx >= mSamplers.size())
+ {
+ LL_WARNS("GLTF_IMPORT") << "Invalid texture indices in imageBufferToTextureUUID" << LL_ENDL;
+ return LLUUID::null;
+ }
+
+ gltf_image& image = mImages[tex.imageIdx];
+ gltf_sampler& sampler = mSamplers[tex.samplerIdx];
+
+ S32 sourceIndex = tex.imageIdx;
+ if (sourceIndex < 0 || sourceIndex >= mGLTFAsset.mImages.size())
+ {
+ LL_WARNS("GLTF_IMPORT") << "Invalid image index: " << sourceIndex << LL_ENDL;
+ return LLUUID::null;
+ }
+
+ LL::GLTF::Image& source_image = mGLTFAsset.mImages[sourceIndex];
+
+ // If the image already has a texture loaded, use it
+ if (source_image.mTexture.notNull())
+ {
+ LL_INFOS("GLTF_IMPORT") << "Using already loaded texture ID: " << source_image.mTexture->getID().asString() << LL_ENDL;
+ return source_image.mTexture->getID();
+ }
+
+ // Create an import material to pass to the texture load function
+ LLImportMaterial material;
+
+ // Try to get the texture filename from the URI
+ if (!source_image.mUri.empty())
+ {
+ std::string filename = source_image.mUri;
+
+ // Extract just the filename from the URI
+ size_t pos = filename.find_last_of("/\\");
+ if (pos != std::string::npos)
+ {
+ filename = filename.substr(pos + 1);
+ }
- // fill an LLSD container with image+sampler data
+ material.mDiffuseMapFilename = filename;
+ material.mDiffuseMapLabel = filename;
+ }
+ else if (source_image.mBufferView >= 0)
+ {
+ // For embedded textures, create a pseudo-filename
+ std::string pseudo_filename = "gltf_embedded_texture_" + std::to_string(sourceIndex) + ".png";
+ material.mDiffuseMapFilename = pseudo_filename;
+ material.mDiffuseMapLabel = pseudo_filename;
+ }
+ else
+ {
+ LL_WARNS("GLTF_IMPORT") << "No URI or buffer data for image" << LL_ENDL;
+ return LLUUID::null;
+ }
+
+ // Create LLSD container with image and sampler data for texture upload
+ LLSD texture_data = LLSD::emptyMap();
- // upload texture
+ // Image data
+ texture_data["width"] = LLSD::Integer(image.width);
+ texture_data["height"] = LLSD::Integer(image.height);
+ texture_data["components"] = LLSD::Integer(image.numChannels);
+ texture_data["bytes_per_component"] = LLSD::Integer(image.bytesPerChannel);
+ texture_data["pixel_type"] = LLSD::Integer(image.pixelType);
- // retrieve UUID
+ // Sampler data
+ texture_data["min_filter"] = LLSD::Integer(sampler.minFilter);
+ texture_data["mag_filter"] = LLSD::Integer(sampler.magFilter);
+ texture_data["wrap_s"] = LLSD::Integer(sampler.wrapS);
+ texture_data["wrap_t"] = LLSD::Integer(sampler.wrapT);
+
+ // Add URI for reference
+ if (!source_image.mUri.empty())
+ {
+ texture_data["uri"] = source_image.mUri;
+ }
+
+ // Check if we have a buffer view for embedded data
+ if (source_image.mBufferView >= 0)
+ {
+ texture_data["has_embedded_data"] = LLSD::Boolean(true);
+ texture_data["buffer_view"] = LLSD::Integer(source_image.mBufferView);
+
+ // Extract embedded data for texture loading
+ if (source_image.mBufferView < mGLTFAsset.mBufferViews.size())
+ {
+ const LL::GLTF::BufferView& buffer_view = mGLTFAsset.mBufferViews[source_image.mBufferView];
+ if (buffer_view.mBuffer < mGLTFAsset.mBuffers.size())
+ {
+ const LL::GLTF::Buffer& buffer = mGLTFAsset.mBuffers[buffer_view.mBuffer];
+ if (buffer_view.mByteOffset + buffer_view.mByteLength <= buffer.mData.size())
+ {
+ // Add embedded data reference to texture_data
+ texture_data["buffer_index"] = LLSD::Integer(buffer_view.mBuffer);
+ texture_data["byte_offset"] = LLSD::Integer(buffer_view.mByteOffset);
+ texture_data["byte_length"] = LLSD::Integer(buffer_view.mByteLength);
+
+ LL_INFOS("GLTF_IMPORT") << "Found embedded texture data: offset=" << buffer_view.mByteOffset
+ << " length=" << buffer_view.mByteLength << LL_ENDL;
+ }
+ }
+ }
+ }
+
+ // Store the texture metadata in the binding field
+ std::ostringstream ostr;
+ LLSDSerialize::toXML(texture_data, ostr);
+ material.mBinding = ostr.str();
+
+ LL_INFOS("GLTF_IMPORT") << "Loading texture: " << material.mDiffuseMapFilename << LL_ENDL;
+
+ // Flag to track if texture was loaded immediately
+ bool texture_loaded = false;
+
+ // Call texture loading function with our import material
+ if (mTextureLoadFunc)
+ {
+ // Increment textures to fetch counter BEFORE calling load function
+ mNumOfFetchingTextures++;
+
+ U32 result = mTextureLoadFunc(material, mOpaqueData);
+
+ // If result is 0, texture is being loaded asynchronously
+ // If result is >0, texture was loaded immediately
+ if (result > 0)
+ {
+ // Texture was loaded immediately, so decrement counter
+ mNumOfFetchingTextures--;
+ texture_loaded = true;
+
+ if (material.getDiffuseMap().notNull())
+ {
+ LL_INFOS("GLTF_IMPORT") << "Texture loaded successfully, ID: " << material.getDiffuseMap().asString() << LL_ENDL;
+
+ // Store the texture in the source image for future reference
+ if (source_image.mTexture.isNull())
+ {
+ // Create and store a texture object using the UUID
+ source_image.mTexture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap());
+ }
+
+ return material.getDiffuseMap();
+ }
+ }
+ else if (result == 0)
+ {
+ LL_INFOS("GLTF_IMPORT") << "Texture loading queued asynchronously for " << material.mDiffuseMapFilename << LL_ENDL;
+ }
+ else // result < 0, indicating error
+ {
+ // Texture loading failed, decrement counter
+ mNumOfFetchingTextures--;
+ LL_WARNS("GLTF_IMPORT") << "Texture loading failed for " << material.mDiffuseMapFilename << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS("GLTF_IMPORT") << "No texture loading function available" << LL_ENDL;
+ }
return LLUUID::null;
}
+