diff options
| author | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2025-05-16 19:10:52 -0400 | 
|---|---|---|
| committer | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2025-05-16 19:10:52 -0400 | 
| commit | 9346015b615c506268a82fff4edf81a13f72ec66 (patch) | |
| tree | aa78fea3d21119d5a7eb3db0b0eb4dccb20d22bf /indra | |
| parent | bb76eae4b814e612ff2b0c62fffc6c3263058d64 (diff) | |
| parent | 47d95f1eae379f16ed0ae320c9bb1a6002186e32 (diff) | |
Merge branch 'geenz/gltf-texture-upload-merge' into geenz/gltf-mesh-import
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/gltf/llgltfloader.cpp | 584 | 
1 files changed, 470 insertions, 114 deletions
| diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 2db803ef3e..7570c33dcf 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); @@ -176,24 +174,19 @@ bool LLGLTFLoader::parseMeshes()                      LLMatrix4 rotation;                      rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);                      mTransform *= rotation; -                      transformation = mTransform; -                                          // adjust the transformation to compensate for mesh normalization                      LLVector3 mesh_scale_vector;                      LLVector3 mesh_translation_vector;                      pModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); -                      LLMatrix4 mesh_translation;                      mesh_translation.setTranslation(mesh_translation_vector);                      mesh_translation *= transformation;                      transformation = mesh_translation; -                      LLMatrix4 mesh_scale;                      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 +226,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 +245,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 +370,6 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&                      vert.weights = glm::vec4(prim.mWeights[i]);                  } -                  vertices.push_back(vert);              } @@ -312,22 +385,18 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&              for (U32 i = 0; i < vertices.size(); i++)              {                  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);                  LLVector4a normal = LLVector4a(vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z);                  vert.setPosition(position); @@ -345,8 +414,6 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&                  weight_list.push_back(LLModel::JointWeight(vertices[i].joints.w, vertices[i].weights.w));                  std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - -                                  std::vector<LLModel::JointWeight> wght;                  F32                               total = 0.f; @@ -377,8 +444,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 +479,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 +555,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 +654,6 @@ bool LLGLTFLoader::parseMaterials()      }      return true; -    */  }  // TODO: convert raw vertex buffers to UUIDs @@ -529,18 +665,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 +701,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 +710,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 +719,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 +728,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); +        } + +        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(); + +    // 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); + +    // 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; -    // fill an LLSD container with image+sampler data +    // Flag to track if texture was loaded immediately +    bool texture_loaded = false; -    // upload texture +    // 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); -    // retrieve UUID +        // 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;  } + | 
