summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/gltf/llgltfloader.cpp377
-rw-r--r--indra/newview/gltf/llgltfloader.h3
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_preview.xml2
3 files changed, 65 insertions, 317 deletions
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index e495abfe75..056d3df1a6 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -623,67 +623,11 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
else if (image.mBufferView >= 0)
{
// For embedded textures (no URI but has buffer data)
- // Extract the texture to a temporary file immediately
- if (image.mBufferView < mGLTFAsset.mBufferViews.size())
+ std::string temp_filename = extractTextureToTempFile(texIndex, "base_color");
+ if (!temp_filename.empty())
{
- const LL::GLTF::BufferView& buffer_view = mGLTFAsset.mBufferViews[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())
- {
- // Extract image data
- const U8* data_ptr = &buffer.mData[buffer_view.mByteOffset];
- U32 data_size = buffer_view.mByteLength;
-
- // Determine the file extension
- std::string extension = ".png"; // Default
- if (!image.mMimeType.empty())
- {
- if (image.mMimeType == "image/jpeg")
- extension = ".jpg";
- else if (image.mMimeType == "image/png")
- extension = ".png";
- }
- else if (data_size >= 4)
- {
- if (data_ptr[0] == 0xFF && data_ptr[1] == 0xD8)
- extension = ".jpg"; // JPEG magic bytes
- else if (data_ptr[0] == 0x89 && data_ptr[1] == 0x50 && data_ptr[2] == 0x4E && data_ptr[3] == 0x47)
- extension = ".png"; // PNG magic bytes
- }
-
- // Create a temporary file
- std::string temp_dir = gDirUtilp->getTempDir();
- std::string temp_filename = temp_dir + gDirUtilp->getDirDelimiter() +
- "gltf_embedded_" + std::to_string(sourceIndex) + extension;
-
- // Write the image data to the temporary file
- std::ofstream temp_file(temp_filename, std::ios::binary);
- if (temp_file.is_open())
- {
- temp_file.write(reinterpret_cast<const char*>(data_ptr), data_size);
- temp_file.close();
-
- // Use the temp file as the texture filename
- impMat.mDiffuseMapFilename = temp_filename;
- impMat.mDiffuseMapLabel = material->mName.empty() ? temp_filename : material->mName;
-
- LL_INFOS("GLTF_IMPORT") << "Extracted embedded texture to: " << temp_filename << LL_ENDL;
- }
- else
- {
- LL_WARNS("GLTF_IMPORT") << "Failed to create temporary file for embedded texture" << LL_ENDL;
-
- LLSD args;
- args["Message"] = "FailedToCreateTempFile";
- args["TEXTURE_INDEX"] = sourceIndex;
- args["TEMP_FILE"] = temp_filename;
- mWarningsArray.append(args);
- }
- }
- }
+ impMat.mDiffuseMapFilename = temp_filename;
+ impMat.mDiffuseMapLabel = material->mName.empty() ? temp_filename : material->mName;
}
}
}
@@ -1730,286 +1674,89 @@ void LLGLTFLoader::uploadMeshes()
// convert raw image buffers to texture UUIDs & assemble into a render material
void LLGLTFLoader::uploadMaterials()
{
- LL_INFOS("GLTF_IMPORT") << "Uploading materials, count: " << mMaterials.size() << LL_ENDL;
-
- for (gltf_render_material& mat : mMaterials)
- {
- 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;
- }
- }
- }
-
- // Process other textures similarly
- if (mat.hasMRTex && mat.metalRoughTexIdx < mTextures.size())
- {
- gltf_texture& gtex = mTextures[mat.metalRoughTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasNormalTex && mat.normalTexIdx < mTextures.size())
- {
- gltf_texture& gtex = mTextures[mat.normalTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasOcclusionTex && mat.occlusionTexIdx < mTextures.size())
- {
- gltf_texture& gtex = mTextures[mat.occlusionTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasEmissiveTex && mat.emissiveTexIdx < mTextures.size())
- {
- gltf_texture& gtex = mTextures[mat.emissiveTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
- }
-
- // 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)
+std::string LLGLTFLoader::extractTextureToTempFile(S32 textureIndex, const std::string& texture_type)
{
- 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];
+ if (textureIndex < 0 || textureIndex >= mGLTFAsset.mTextures.size())
+ return "";
- S32 sourceIndex = tex.imageIdx;
+ S32 sourceIndex = mGLTFAsset.mTextures[textureIndex].mSource;
if (sourceIndex < 0 || sourceIndex >= mGLTFAsset.mImages.size())
- {
- LL_WARNS("GLTF_IMPORT") << "Invalid image index: " << sourceIndex << LL_ENDL;
- return LLUUID::null;
- }
+ return "";
- LL::GLTF::Image& source_image = mGLTFAsset.mImages[sourceIndex];
+ LL::GLTF::Image& image = mGLTFAsset.mImages[sourceIndex];
- // If the image already has a texture loaded, use it
- if (source_image.mTexture.notNull())
+ // Handle URI-based textures
+ if (!image.mUri.empty())
{
- LL_INFOS("GLTF_IMPORT") << "Using already loaded texture ID: " << source_image.mTexture->getID().asString() << LL_ENDL;
- return source_image.mTexture->getID();
+ return image.mUri; // Return URI directly
}
- // 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())
+ // Handle embedded textures
+ if (image.mBufferView >= 0)
{
- 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)
+ if (image.mBufferView < mGLTFAsset.mBufferViews.size())
{
- 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];
+ const LL::GLTF::BufferView& buffer_view = mGLTFAsset.mBufferViews[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);
+ // Extract image data
+ const U8* data_ptr = &buffer.mData[buffer_view.mByteOffset];
+ U32 data_size = 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);
+ // Determine the file extension
+ std::string extension = ".png"; // Default
+ if (!image.mMimeType.empty())
+ {
+ if (image.mMimeType == "image/jpeg")
+ extension = ".jpg";
+ else if (image.mMimeType == "image/png")
+ extension = ".png";
+ }
+ else if (data_size >= 4)
+ {
+ if (data_ptr[0] == 0xFF && data_ptr[1] == 0xD8)
+ extension = ".jpg"; // JPEG magic bytes
+ else if (data_ptr[0] == 0x89 && data_ptr[1] == 0x50 && data_ptr[2] == 0x4E && data_ptr[3] == 0x47)
+ extension = ".png"; // PNG magic bytes
+ }
- // 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;
+ // Create a temporary file
+ std::string temp_dir = gDirUtilp->getTempDir();
+ std::string temp_filename = temp_dir + gDirUtilp->getDirDelimiter() +
+ "gltf_embedded_" + texture_type + "_" + std::to_string(sourceIndex) + extension;
- if (material.getDiffuseMap().notNull())
- {
- LL_INFOS("GLTF_IMPORT") << "Texture loaded successfully, ID: " << material.getDiffuseMap().asString() << LL_ENDL;
+ // Write the image data to the temporary file
+ std::ofstream temp_file(temp_filename, std::ios::binary);
+ if (temp_file.is_open())
+ {
+ temp_file.write(reinterpret_cast<const char*>(data_ptr), data_size);
+ temp_file.close();
- // 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());
+ LL_INFOS("GLTF_IMPORT") << "Extracted embedded " << texture_type << " texture to: " << temp_filename << LL_ENDL;
+ return temp_filename;
+ }
+ else
+ {
+ LL_WARNS("GLTF_IMPORT") << "Failed to create temporary file for " << texture_type << " texture: " << temp_filename << LL_ENDL;
+
+ LLSD args;
+ args["Message"] = "FailedToCreateTempFile";
+ args["TEXTURE_INDEX"] = sourceIndex;
+ args["TEXTURE_TYPE"] = texture_type;
+ args["TEMP_FILE"] = temp_filename;
+ mWarningsArray.append(args);
+ }
}
-
- 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;
+ return "";
}
void LLGLTFLoader::notifyUnsupportedExtension(bool unsupported)
diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h
index 393df8c4ee..e0b3664012 100644
--- a/indra/newview/gltf/llgltfloader.h
+++ b/indra/newview/gltf/llgltfloader.h
@@ -230,7 +230,8 @@ private:
glm::mat4 computeGltfToViewerSkeletonTransform(const joints_data_map_t& joints_data_map, S32 gltf_node_index, const std::string& joint_name) const;
bool checkForXYrotation(const LL::GLTF::Skin& gltf_skin, S32 joint_idx, S32 bind_indx);
void checkForXYrotation(const LL::GLTF::Skin& gltf_skin);
- LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
+
+ std::string extractTextureToTempFile(S32 textureIndex, const std::string& texture_type);
void notifyUnsupportedExtension(bool unsupported);
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index 4c60320a94..80b6427738 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -71,7 +71,7 @@
<string name="IgnoredExtension">Model uses unsupported extension: [EXT], related material properties are ignored</string>
<string name="UnsupportedExtension">Unable to load model, unsupported extension: [EXT]</string>
<string name="TooManyMeshParts">Model contains [PART_COUNT] mesh parts. Maximum allowed: [LIMIT]</string>
- <string name="FailedToCreateTempFile">Failed to create temporary file for embedded texture [TEXTURE_INDEX]: [TEMP_FILE]</string>
+ <string name="FailedToCreateTempFile">Failed to create temporary file for embedded [TEXTURE_TYPE] texture [TEXTURE_INDEX]: [TEMP_FILE]</string>
<string name="SkinJointsOverLimit">Skin [SKIN_INDEX] defines [JOINT_COUNT] compatible joints, maximum is: [MAX]. Unused joints will be stripped on per model basis.</string>
<string name="ModelTooManyJoint">Model [MODEL_NAME] uses [JOINT_COUNT], maximum: [MAX], upload might fail</string>