From c9ebb970ee916ace16e88508dc1a178336a91d52 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Wed, 1 Jun 2022 14:37:20 -0600
Subject: SL-17214 re-work gltf data organization

---
 indra/llprimitive/llgltfloader.cpp | 138 +++++++++++++++++++++++++++----------
 indra/llprimitive/llgltfloader.h   |  70 +++++++++----------
 2 files changed, 132 insertions(+), 76 deletions(-)

(limited to 'indra')

diff --git a/indra/llprimitive/llgltfloader.cpp b/indra/llprimitive/llgltfloader.cpp
index bc9c4760f7..3ec11f70c6 100644
--- a/indra/llprimitive/llgltfloader.cpp
+++ b/indra/llprimitive/llgltfloader.cpp
@@ -45,6 +45,9 @@
 // TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE
 #include "tinygltf\tiny_gltf.h"
 
+
+// TODO: includes inherited from dae loader.  Validate / prune
+
 #include <boost/lexical_cast.hpp>
 
 #include "llsdserialize.h"
@@ -120,9 +123,9 @@ bool LLGLTFLoader::OpenFile(const std::string &filename)
     if (!mGltfLoaded)
     {
         if (!warn_msg.empty())
-            LL_WARNS() << "gltf load warning: " << warn_msg.c_str() << LL_ENDL;
+            LL_WARNS("GLTF_IMPORT") << "gltf load warning: " << warn_msg.c_str() << LL_ENDL;
         if (!error_msg.empty())
-            LL_WARNS() << "gltf load error: " << error_msg.c_str() << LL_ENDL;
+            LL_WARNS("GLTF_IMPORT") << "gltf load error: " << error_msg.c_str() << LL_ENDL;
         return false;
     }
 
@@ -251,10 +254,11 @@ bool LLGLTFLoader::parseMaterials()
     for (auto in_tex : mGltfModel.textures)
     {
         gltf_texture tex;
-        tex.image_idx   = in_tex.source;
-        tex.sampler_idx = in_tex.sampler;
+        tex.imageIdx   = in_tex.source;
+        tex.samplerIdx = in_tex.sampler;
+        tex.imageUuid.setNull();
 
-        if (tex.image_idx >= mImages.size() || tex.sampler_idx >= mSamplers.size())
+        if (tex.imageIdx >= mImages.size() || tex.samplerIdx >= mSamplers.size())
         {
             LL_WARNS("GLTF_IMPORT") << "Texture sampler/image index error" << LL_ENDL;
             return false;
@@ -269,53 +273,53 @@ bool LLGLTFLoader::parseMaterials()
         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.hasNormalTex = gltf_material.normalTexture.index >= 0;
         mat.normalTexIdx = gltf_material.normalTexture.index;
-        mat.normalTexCoordIdx = gltf_material.normalTexture.texCoord;
+        mat.normalTexCoords = gltf_material.normalTexture.texCoord;
 
         mat.occlusionScale = gltf_material.occlusionTexture.strength;
-        mat.hasOcclusionTex = gltf_material.occlusionTexture.index > 0;
+        mat.hasOcclusionTex = gltf_material.occlusionTexture.index >= 0;
         mat.occlusionTexIdx = gltf_material.occlusionTexture.index;
-        mat.occlusionTexCoordIdx = gltf_material.occlusionTexture.texCoord;
+        mat.occlusionTexCoords = gltf_material.occlusionTexture.texCoord;
 
         mat.emissiveColor.set(gltf_material.emissiveFactor.data());
-        mat.hasEmissiveTex = gltf_material.emissiveTexture.index > 0;
-        mat.emissiveColorTexIdx = gltf_material.emissiveTexture.index;
-        mat.emissiveColorTexCoordIdx = gltf_material.emissiveTexture.texCoord;
+        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;
 
-        tinygltf::PbrMetallicRoughness& pbr = gltf_material.pbrMetallicRoughness;
-        mat.hasPBR = true;
-
-        mat.pbr.baseColor.set(pbr.baseColorFactor.data());
-        mat.pbr.hasBaseTex = pbr.baseColorTexture.index > 0;
-        mat.pbr.baseColorTexIdx = pbr.baseColorTexture.index;
-        mat.pbr.baseColorTexCoordIdx = pbr.baseColorTexture.texCoord;
-
-        mat.pbr.metalness = pbr.metallicFactor;
-        mat.pbr.roughness = pbr.roughnessFactor;
-        mat.pbr.hasMRTex = pbr.metallicRoughnessTexture.index > 0;
-        mat.pbr.metalRoughTexIdx = pbr.metallicRoughnessTexture.index;
-        mat.pbr.metalRoughTexCoordIdx = pbr.metallicRoughnessTexture.texCoord;
-
-        if ((mat.hasNormalTex    && (mat.normalTexIdx         >= mTextures.size())) ||
-            (mat.hasOcclusionTex && (mat.occlusionTexIdx      >= mTextures.size())) ||
-            (mat.hasEmissiveTex  && (mat.emissiveColorTexIdx  >= mTextures.size())) ||
-            (mat.pbr.hasBaseTex  && (mat.pbr.baseColorTexIdx  >= mTextures.size())) ||
-            (mat.pbr.hasMRTex    && (mat.pbr.metalRoughTexIdx >= mTextures.size())))
+        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.normalTexCoordIdx         > 2)) ||    // mesh can have up to 3 sets of UV
-            (mat.hasOcclusionTex && (mat.occlusionTexCoordIdx      > 2)) ||
-            (mat.hasEmissiveTex  && (mat.emissiveColorTexCoordIdx  > 2)) ||
-            (mat.pbr.hasBaseTex  && (mat.pbr.baseColorTexCoordIdx  > 2)) ||
-            (mat.pbr.hasMRTex    && (mat.pbr.metalRoughTexCoordIdx > 2)))
+        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)))
         {
             LL_WARNS("GLTF_IMPORT") << "Image texcoord index error" << LL_ENDL;
             return false;
@@ -333,10 +337,68 @@ void LLGLTFLoader::uploadMeshes()
     llassert(0);
 }
 
-// TODO: convert raw index buffers to UUIDs
+// convert raw image buffers to texture UUIDs & assemble into a render material
 void LLGLTFLoader::uploadMaterials()
 {
-    //llassert(0);
+    for (gltf_render_material mat : mMaterials) // Initially 1 material per gltf file, but design for multiple
+    {
+        if (mat.hasBaseTex)
+        {
+            gltf_texture& gtex = mTextures[mat.baseColorTexIdx];
+            if (gtex.imageUuid.isNull()) 
+            {
+                gtex.imageUuid = imageBufferToTextureUUID(gtex);
+            }
+        }
+
+        if (mat.hasMRTex)
+        {
+            gltf_texture& gtex = mTextures[mat.metalRoughTexIdx];
+            if (gtex.imageUuid.isNull())
+            {
+                gtex.imageUuid = imageBufferToTextureUUID(gtex);
+            }
+        }
+
+        if (mat.hasNormalTex)
+        {
+            gltf_texture& gtex = mTextures[mat.normalTexIdx];
+            if (gtex.imageUuid.isNull())
+            {
+                gtex.imageUuid = imageBufferToTextureUUID(gtex);
+            }
+        }
 
+        if (mat.hasOcclusionTex)
+        {
+            gltf_texture& gtex = mTextures[mat.occlusionTexIdx];
+            if (gtex.imageUuid.isNull())
+            {
+                gtex.imageUuid = imageBufferToTextureUUID(gtex);
+            }
+        }
+
+        if (mat.hasEmissiveTex)
+        {
+            gltf_texture& gtex = mTextures[mat.emissiveTexIdx];
+            if (gtex.imageUuid.isNull())
+            {
+                gtex.imageUuid = imageBufferToTextureUUID(gtex);
+            }
+        }
+    }
 }
 
+LLUUID LLGLTFLoader::imageBufferToTextureUUID(const gltf_texture& tex)
+{
+    //gltf_image& image = mImages[tex.imageIdx];
+    //gltf_sampler& sampler = mSamplers[tex.samplerIdx];
+
+    // fill an LLSD container with image+sampler data
+
+    // upload texture
+
+    // retrieve UUID
+
+    return LLUUID::null;
+}
diff --git a/indra/llprimitive/llgltfloader.h b/indra/llprimitive/llgltfloader.h
index 08e9836d07..24496f6324 100644
--- a/indra/llprimitive/llgltfloader.h
+++ b/indra/llprimitive/llgltfloader.h
@@ -32,19 +32,21 @@
 #include "llglheaders.h"
 #include "llmodelloader.h"
 
+// gltf_* structs are temporary, used to organize the subset of data that eventually goes into the material LLSD
+
 typedef struct // gltf sampler
 {   // Uses GL enums
     S32 minFilter;      // GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR or GL_LINEAR_MIPMAP_LINEAR
     S32 magFilter;      // GL_NEAREST or GL_LINEAR
     S32 wrapS;          // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT
     S32 wrapT;          // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT
-    //S32 wrapR;        // seen in some sample files, but not part of glTF 2.0 spec. Ignored.
+    //S32 wrapR;        // Found in some sample files, but not part of glTF 2.0 spec. Ignored.
     std::string name;   // optional, currently unused
     // extensions and extras are sampler optional fields that we don't support - at least initially 
 } gltf_sampler;
 
 typedef struct // gltf image
-{   // Note that glTF images are defined with row 0 at the top
+{   // Note that glTF images are defined with row 0 at the top (opposite of OpenGL)
     U8* data;               // ptr to decoded image data
     U32 size;               // in bytes, regardless of channel width
     U32 width;
@@ -56,34 +58,19 @@ typedef struct // gltf image
 
 typedef struct // texture
 {
-    U32 image_idx;
-    U32 sampler_idx;
+    U32 imageIdx;
+    U32 samplerIdx;
+    LLUUID imageUuid = LLUUID::null;
 } gltf_texture;
 
-
-// TODO: 2022-05 DJH add UUIDs for each texture
-typedef struct  // gltf_pbrMR_material
-{
-    // scalar values
-    LLColor4    baseColor;      // linear encoding. Multiplied with vertex color, if present.
-    double      metalness;
-    double      roughness;
-
-    // textures
-    U32 baseColorTexIdx;        // always sRGB encoded
-    U32 baseColorTexCoordIdx;
-
-    U32 metalRoughTexIdx;       // always linear, roughness in G channel, metalness in B channel
-    U32 metalRoughTexCoordIdx;
-
-    bool    hasBaseTex, hasMRTex;
-} gltf_pbr;
-
 typedef struct // render material
 {
     std::string name;
 
     // scalar values
+    LLColor4    baseColor;      // linear encoding. Multiplied with vertex color, if present.
+    double      metalness;
+    double      roughness;
     double      normalScale;    // scale applies only to X,Y components of normal
     double      occlusionScale; // strength multiplier for occlusion
     LLColor4    emissiveColor;  // emissive mulitiplier, assumed linear encoding (spec 2.0 is silent)
@@ -91,20 +78,26 @@ typedef struct // render material
     double      alphaMask;      
 
     // textures
-    U32 normalTexIdx;           // linear, valid range R[0-1], G[0-1], B[0.5-1]. Normal = texel * 2 - vec3(1.0)   
-    U32 normalTexCoordIdx;
-
-    U32 occlusionTexIdx;        // linear, occlusion in R channel, 0 meaning fully occluded, 1 meaning not occluded
-    U32 occlusionTexCoordIdx;
-
-    U32 emissiveColorTexIdx;    // always stored as sRGB, in nits (candela / meter^2)
-    U32 emissiveColorTexCoordIdx;
+    U32 baseColorTexIdx;    // always sRGB encoded
+    U32 metalRoughTexIdx;   // always linear, roughness in G channel, metalness in B channel
+    U32 normalTexIdx;       // linear, valid range R[0-1], G[0-1], B[0.5-1]. Normal = texel * 2 - vec3(1.0)   
+    U32 occlusionTexIdx;    // linear, occlusion in R channel, 0 meaning fully occluded, 1 meaning not occluded
+    U32 emissiveTexIdx;     // always stored as sRGB, in nits (candela / meter^2)
+
+    // texture coordinates
+    U32 baseColorTexCoords;
+    U32 metalRoughTexCoords;
+    U32 normalTexCoords;
+    U32 occlusionTexCoords;
+    U32 emissiveTexCoords;
 
     // TODO: Add traditional (diffuse, normal, specular) UUIDs here, or add this struct to LL_TextureEntry??
 
     bool        hasPBR;
-    bool        hasNormalTex, hasOcclusionTex, hasEmissiveTex;
-    gltf_pbr    pbr;
+    bool        hasBaseTex, hasMRTex, hasNormalTex, hasOcclusionTex, hasEmissiveTex;
+
+    // This field is populated after upload
+    LLUUID      material_uuid = LLUUID::null;
 
 } gltf_render_material;
 
@@ -112,7 +105,7 @@ typedef struct  // gltf_mesh
 {
     std::string name;
 
-    // TODO DJH 2022-04
+    // TODO add mesh import DJH 2022-04
 
 } gltf_mesh;
 
@@ -157,16 +150,17 @@ protected:
     std::vector<gltf_sampler>           mSamplers;
 
 private:
-    U32  mGeneratedModelLimit;  // Attempt to limit amount of generated submodels
-//    bool mPreprocessGLTF;
-    
     bool parseMeshes();
     void uploadMeshes();
     bool parseMaterials();
     void uploadMaterials();
     bool populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh);
+    LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
+
+    U32  mGeneratedModelLimit;  // Attempt to limit amount of generated submodels
+    //    bool mPreprocessGLTF;
 
-    /*
+    /*  Inherited from dae loader - unknown how useful here
     void processElement(gltfElement *element, bool &badElement, GLTF *gltf);
     void processGltfModel(LLModel *model, GLTF *gltf, gltfElement *pRoot, gltfMesh *mesh, gltfSkin *skin);
 
-- 
cgit v1.2.3