diff options
Diffstat (limited to 'indra/newview')
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/gltf/asset.cpp | 198 | ||||
| -rw-r--r-- | indra/newview/gltf/asset.h | 13 | ||||
| -rw-r--r-- | indra/newview/gltf/buffer_util.h | 11 | ||||
| -rw-r--r-- | indra/newview/gltf/llgltfloader.cpp | 1710 | ||||
| -rw-r--r-- | indra/newview/gltf/llgltfloader.h | 203 | ||||
| -rw-r--r-- | indra/newview/gltfscenemanager.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llfilepicker.cpp | 6 | ||||
| -rw-r--r-- | indra/newview/llfloaterbvhpreview.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/llfloaterbvhpreview.h | 2 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelpreview.cpp | 7 | ||||
| -rw-r--r-- | indra/newview/llmaterialeditor.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llmodelpreview.cpp | 52 | ||||
| -rw-r--r-- | indra/newview/llskinningutil.cpp | 9 | ||||
| -rw-r--r-- | indra/newview/llvoavatar.cpp | 8 | ||||
| -rw-r--r-- | indra/newview/llvoavatar.h | 2 | ||||
| -rw-r--r-- | indra/newview/llvoavatarself.cpp | 6 | ||||
| -rw-r--r-- | indra/newview/llvoavatarself.h | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_model_preview.xml | 20 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 5 | 
20 files changed, 127 insertions, 2138 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dee3d5ed59..98151e2f4d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -76,7 +76,6 @@ set(viewer_SOURCE_FILES      gltf/accessor.cpp      gltf/primitive.cpp      gltf/animation.cpp -    gltf/llgltfloader.cpp      groupchatlistener.cpp      llaccountingcostmanager.cpp      llaisapi.cpp @@ -747,7 +746,6 @@ set(viewer_HEADER_FILES      gltf/buffer_util.h      gltf/primitive.h      gltf/animation.h -    gltf/llgltfloader.h      llaccountingcost.h      llaccountingcostmanager.h      llaisapi.h diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 8c9f77686a..c210b9c61d 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -50,10 +50,6 @@ namespace LL              "KHR_texture_transform"          }; -        static std::unordered_set<std::string> ExtensionsIgnored = { -            "KHR_materials_pbrSpecularGlossiness" -        }; -          Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode)          {              if (alpha_mode == "OPAQUE") @@ -476,14 +472,11 @@ void Asset::update()              for (auto& image : mImages)              { -                if (image.mLoadIntoTexturePipe) -                { -                    if (image.mTexture.notNull()) -                    { // HACK - force texture to be loaded full rez -                        // TODO: calculate actual vsize -                        image.mTexture->addTextureStats(2048.f * 2048.f); -                        image.mTexture->setBoostLevel(LLViewerTexture::BOOST_HIGH); -                    } +                if (image.mTexture.notNull()) +                { // HACK - force texture to be loaded full rez +                    // TODO: calculate actual vsize +                    image.mTexture->addTextureStats(2048.f * 2048.f); +                    image.mTexture->setBoostLevel(LLViewerTexture::BOOST_HIGH);                  }              }          } @@ -493,23 +486,18 @@ void Asset::update()  bool Asset::prep()  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; -    // check required extensions +    // check required extensions and fail if not supported +    bool unsupported = false;      for (auto& extension : mExtensionsRequired)      {          if (ExtensionsSupported.find(extension) == ExtensionsSupported.end())          { -            if (ExtensionsIgnored.find(extension) == ExtensionsIgnored.end()) -            { -                LL_WARNS() << "Unsupported extension: " << extension << LL_ENDL; -                mUnsupportedExtensions.push_back(extension); -            } -            else -            { -                mIgnoredExtensions.push_back(extension); -            } +            LL_WARNS() << "Unsupported extension: " << extension << LL_ENDL; +            unsupported = true;          }      } -    if (mUnsupportedExtensions.size() > 0) + +    if (unsupported)      {          return false;      } @@ -525,7 +513,7 @@ bool Asset::prep()      for (auto& image : mImages)      { -        if (!image.prep(*this, mLoadIntoVRAM)) +        if (!image.prep(*this))          {              return false;          } @@ -554,106 +542,102 @@ bool Asset::prep()              return false;          }      } -    if (mLoadIntoVRAM) -    { -        // prepare vertex buffers -        // material count is number of materials + 1 for default material -        U32 mat_count = (U32) mMaterials.size() + 1; +    // prepare vertex buffers + +    // material count is number of materials + 1 for default material +    U32 mat_count = (U32) mMaterials.size() + 1; -        if (LLGLSLShader::sCurBoundShaderPtr == nullptr) -        { // make sure a shader is bound to satisfy mVertexBuffer->setBuffer -            gDebugProgram.bind(); +    if (LLGLSLShader::sCurBoundShaderPtr == nullptr) +    { // make sure a shader is bound to satisfy mVertexBuffer->setBuffer +        gDebugProgram.bind(); +    } + +    for (S32 double_sided = 0; double_sided < 2; ++double_sided) +    { +        RenderData& rd = mRenderData[double_sided]; +        for (U32 i = 0; i < LLGLSLShader::NUM_GLTF_VARIANTS; ++i) +        { +            rd.mBatches[i].resize(mat_count);          } -        for (S32 double_sided = 0; double_sided < 2; ++double_sided) +        // for each material +        for (S32 mat_id = -1; mat_id < (S32)mMaterials.size(); ++mat_id)          { -            RenderData& rd = mRenderData[double_sided]; -            for (U32 i = 0; i < LLGLSLShader::NUM_GLTF_VARIANTS; ++i) +            // for each shader variant +            U32 vertex_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 }; +            U32 index_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 }; + +            S32 ds_mat = mat_id == -1 ? 0 : mMaterials[mat_id].mDoubleSided; +            if (ds_mat != double_sided)              { -                rd.mBatches[i].resize(mat_count); +                continue;              } -            // for each material -            for (S32 mat_id = -1; mat_id < (S32)mMaterials.size(); ++mat_id) +            for (U32 variant = 0; variant < LLGLSLShader::NUM_GLTF_VARIANTS; ++variant)              { -                // for each shader variant -                U32 vertex_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 }; -                U32 index_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 }; - -                S32 ds_mat = mat_id == -1 ? 0 : mMaterials[mat_id].mDoubleSided; -                if (ds_mat != double_sided) +                U32 attribute_mask = 0; +                // for each mesh +                for (auto& mesh : mMeshes)                  { -                    continue; -                } - -                for (U32 variant = 0; variant < LLGLSLShader::NUM_GLTF_VARIANTS; ++variant) -                { -                    U32 attribute_mask = 0; -                    // for each mesh -                    for (auto& mesh : mMeshes) +                    // for each primitive +                    for (auto& primitive : mesh.mPrimitives)                      { -                        // for each primitive -                        for (auto& primitive : mesh.mPrimitives) +                        if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant)                          { -                            if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant) -                            { -                                // accumulate vertex and index counts -                                primitive.mVertexOffset = vertex_count[variant]; -                                primitive.mIndexOffset = index_count[variant]; +                            // accumulate vertex and index counts +                            primitive.mVertexOffset = vertex_count[variant]; +                            primitive.mIndexOffset = index_count[variant]; -                                vertex_count[variant] += primitive.getVertexCount(); -                                index_count[variant] += primitive.getIndexCount(); +                            vertex_count[variant] += primitive.getVertexCount(); +                            index_count[variant] += primitive.getIndexCount(); -                                // all primitives of a given variant and material should all have the same attribute mask -                                llassert(attribute_mask == 0 || primitive.mAttributeMask == attribute_mask); -                                attribute_mask |= primitive.mAttributeMask; -                            } +                            // all primitives of a given variant and material should all have the same attribute mask +                            llassert(attribute_mask == 0 || primitive.mAttributeMask == attribute_mask); +                            attribute_mask |= primitive.mAttributeMask;                          }                      } +                } -                    // allocate vertex buffer and pack it -                    if (vertex_count[variant] > 0) -                    { -                        U32 mat_idx = mat_id + 1; -                        #if 0 -                        LLVertexBuffer* vb = new LLVertexBuffer(attribute_mask); +                // allocate vertex buffer and pack it +                if (vertex_count[variant] > 0) +                { +                    U32 mat_idx = mat_id + 1; +                    LLVertexBuffer* vb = new LLVertexBuffer(attribute_mask); -                        rd.mBatches[variant][mat_idx].mVertexBuffer = vb; -                        vb->allocateBuffer(vertex_count[variant], -                            index_count[variant] * 2); // hack double index count... TODO: find a better way to indicate 32-bit indices will be used -                        vb->setBuffer(); +                    rd.mBatches[variant][mat_idx].mVertexBuffer = vb; +                    vb->allocateBuffer(vertex_count[variant], +                        index_count[variant] * 2); // hack double index count... TODO: find a better way to indicate 32-bit indices will be used +                    vb->setBuffer(); -                        for (auto& mesh : mMeshes) +                    for (auto& mesh : mMeshes) +                    { +                        for (auto& primitive : mesh.mPrimitives)                          { -                            for (auto& primitive : mesh.mPrimitives) +                            if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant)                              { -                                if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant) -                                { -                                    primitive.upload(vb); -                                } +                                primitive.upload(vb);                              }                          } +                    } -                        vb->unmapBuffer(); +                    vb->unmapBuffer(); -                        vb->unbind(); -                        #endif -                    } +                    vb->unbind();                  }              }          } +    } -        // sanity check that all primitives have a vertex buffer -        for (auto& mesh : mMeshes) +    // sanity check that all primitives have a vertex buffer +    for (auto& mesh : mMeshes) +    { +        for (auto& primitive : mesh.mPrimitives)          { -            for (auto& primitive : mesh.mPrimitives) -            { -                //llassert(primitive.mVertexBuffer.notNull()); -            } +            llassert(primitive.mVertexBuffer.notNull());          }      } -    #if 0 +      // build render batches      for (S32 node_id = 0; node_id < mNodes.size(); ++node_id)      { @@ -680,7 +664,6 @@ bool Asset::prep()              }          }      } -    #endif      return true;  } @@ -689,10 +672,9 @@ Asset::Asset(const Value& src)      *this = src;  } -bool Asset::load(std::string_view filename, bool loadIntoVRAM) +bool Asset::load(std::string_view filename)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; -    mLoadIntoVRAM = loadIntoVRAM;      mFilename = filename;      std::string ext = gDirUtilp->getExtension(mFilename); @@ -710,7 +692,7 @@ bool Asset::load(std::string_view filename, bool loadIntoVRAM)          }          else if (ext == "glb")          { -            return loadBinary(str, mLoadIntoVRAM); +            return loadBinary(str);          }          else          { @@ -727,9 +709,8 @@ bool Asset::load(std::string_view filename, bool loadIntoVRAM)      return false;  } -bool Asset::loadBinary(const std::string& data, bool loadIntoVRAM) +bool Asset::loadBinary(const std::string& data)  { -    mLoadIntoVRAM = loadIntoVRAM;      // load from binary gltf      const U8* ptr = (const U8*)data.data();      const U8* end = ptr + data.size(); @@ -954,9 +935,8 @@ void Asset::eraseBufferView(S32 bufferView)  LLViewerFetchedTexture* fetch_texture(const LLUUID& id); -bool Image::prep(Asset& asset, bool loadIntoVRAM) +bool Image::prep(Asset& asset)  { -    mLoadIntoTexturePipe = loadIntoVRAM;      LLUUID id;      if (mUri.size() == UUID_STR_SIZE && LLUUID::parseUUID(mUri, &id) && id.notNull())      { // loaded from an asset, fetch the texture from the asset system @@ -971,12 +951,12 @@ bool Image::prep(Asset& asset, bool loadIntoVRAM)      { // embedded in a buffer, load the texture from the buffer          BufferView& bufferView = asset.mBufferViews[mBufferView];          Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; -        if (mLoadIntoTexturePipe) -        { -            U8* data = buffer.mData.data() + bufferView.mByteOffset; -            mTexture = LLViewerTextureManager::getFetchedTextureFromMemory(data, bufferView.mByteLength, mMimeType); -        } -        else if (mTexture.isNull() && mLoadIntoTexturePipe) + +        U8* data = buffer.mData.data() + bufferView.mByteOffset; + +        mTexture = LLViewerTextureManager::getFetchedTextureFromMemory(data, bufferView.mByteLength, mMimeType); + +        if (mTexture.isNull())          {              LL_WARNS("GLTF") << "Failed to load image from buffer:" << LL_ENDL;              LL_WARNS("GLTF") << "  image: " << mName << LL_ENDL; @@ -991,12 +971,12 @@ bool Image::prep(Asset& asset, bool loadIntoVRAM)          std::string img_file = dir + gDirUtilp->getDirDelimiter() + mUri;          LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(img_file); -        if (tracking_id.notNull() && mLoadIntoTexturePipe) +        if (tracking_id.notNull())          {              LLUUID world_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id);              mTexture = LLViewerTextureManager::getFetchedTexture(world_id);          } -        else if (mLoadIntoTexturePipe) +        else          {              LL_WARNS("GLTF") << "Failed to load image from file:" << LL_ENDL;              LL_WARNS("GLTF") << "  image: " << mName << LL_ENDL; @@ -1011,7 +991,7 @@ bool Image::prep(Asset& asset, bool loadIntoVRAM)          return false;      } -    if (!asset.mFilename.empty() && mLoadIntoTexturePipe) +    if (!asset.mFilename.empty())      { // local preview, boost image so it doesn't discard and force to save raw image in case we save out or upload          mTexture->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);          mTexture->forceToSaveRawImage(0, F32_MAX); diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index b9554d753c..27821659db 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -286,7 +286,6 @@ namespace LL              void serialize(boost::json::object& dst) const;          }; -        // Image is for images that we want to load for the given asset.  This acts as an interface into the viewer's texture pipe.          class Image          {          public: @@ -302,8 +301,6 @@ namespace LL              S32 mBits = -1;              S32 mPixelType = -1; -            bool mLoadIntoTexturePipe = false; -              LLPointer<LLViewerFetchedTexture> mTexture;              const Image& operator=(const Value& src); @@ -319,7 +316,7 @@ namespace LL              // preserve only uri and name              void clearData(Asset& asset); -            bool prep(Asset& asset, bool loadIntoVRAM); +            bool prep(Asset& asset);          };          // Render Batch -- vertex buffer and list of primitives to render using @@ -394,10 +391,6 @@ namespace LL              // UBO for storing material data              U32 mMaterialsUBO = 0; -            bool mLoadIntoVRAM = false; - -            std::vector<std::string> mUnsupportedExtensions; -            std::vector<std::string> mIgnoredExtensions;              // prepare for first time use              bool prep(); @@ -435,12 +428,12 @@ namespace LL              // accepts .gltf and .glb files              // Any existing data will be lost              // returns result of prep() on success -            bool load(std::string_view filename, bool loadIntoVRAM); +            bool load(std::string_view filename);              // load .glb contents from memory              // data - binary contents of .glb file              // returns result of prep() on success -            bool loadBinary(const std::string& data, bool loadIntoVRAM); +            bool loadBinary(const std::string& data);              const Asset& operator=(const Value& src);              void serialize(boost::json::object& dst) const; diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index be36c5e90b..ef9bba8128 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -159,12 +159,6 @@ namespace LL          }          template<> -        inline void copyVec3<F32, LLColor4U>(F32* src, LLColor4U& dst) -        { -            dst.set((U8)(src[0] * 255.f), (U8)(src[1] * 255.f), (U8)(src[2] * 255.f), 255); -        } - -        template<>          inline void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)          {              dst.set((U8)(src[0]), (U8)(src[1]), (U8)(src[2]), 255); @@ -375,11 +369,6 @@ namespace LL          template<class T>          inline void copy(Asset& asset, Accessor& accessor, LLStrider<T>& dst)          { -            if (accessor.mBufferView == INVALID_INDEX) -            { -                LL_WARNS("GLTF") << "Invalid buffer" << LL_ENDL; -                return; -            }              const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];              const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];              const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp deleted file mode 100644 index 7ae255e054..0000000000 --- a/indra/newview/gltf/llgltfloader.cpp +++ /dev/null @@ -1,1710 +0,0 @@ -/** - * @file LLGLTFLoader.cpp - * @brief LLGLTFLoader class implementation - * - * $LicenseInfo:firstyear=2022&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2022, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llgltfloader.h" -#include "meshoptimizer.h" -#include <glm/gtc/packing.hpp> - -// Import & define single-header gltf import/export lib -#define TINYGLTF_IMPLEMENTATION -#define TINYGLTF_USE_CPP14  // default is C++ 11 - -// tinygltf by default loads image files using STB -#define STB_IMAGE_IMPLEMENTATION -// to use our own image loading: -// 1. replace this definition with TINYGLTF_NO_STB_IMAGE -// 2. provide image loader callback with TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data) - -// tinygltf saves image files using STB -#define STB_IMAGE_WRITE_IMPLEMENTATION -// similarly, can override with TINYGLTF_NO_STB_IMAGE_WRITE and TinyGLTF::SetImageWriter(fxn, data) - -// Additionally, disable inclusion of STB header files entirely with -// TINYGLTF_NO_INCLUDE_STB_IMAGE -// TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE -#include "tinygltf/tiny_gltf.h" - - -// TODO: includes inherited from dae loader.  Validate / prune - -#include "llsdserialize.h" -#include "lljoint.h" -#include "llbase64.h" -#include "lldir.h" - -#include "llmatrix4a.h" - -#include <boost/regex.hpp> -#include <boost/algorithm/string/replace.hpp> -#include <fstream> - -static const std::string lod_suffix[LLModel::NUM_LODS] = -{ -    "_LOD0", -    "_LOD1", -    "_LOD2", -    "", -    "_PHYS", -}; - -// Premade rotation matrix, GLTF is Y-up while SL is Z-up -static const glm::mat4 coord_system_rotation( -    1.f, 0.f, 0.f, 0.f, -    0.f, 0.f, 1.f, 0.f, -    0.f, -1.f, 0.f, 0.f, -    0.f, 0.f, 0.f, 1.f -); - - -static const glm::mat4 coord_system_rotationxy( -    0.f, 1.f, 0.f, 0.f, -    -1.f, 0.f, 0.f, 0.f, -    0.f, 0.f, 1.f, 0.f, -    0.f, 0.f, 0.f, 1.f -); - -LLGLTFLoader::LLGLTFLoader(std::string filename, -    S32                                 lod, -    LLModelLoader::load_callback_t      load_cb, -    LLModelLoader::joint_lookup_func_t  joint_lookup_func, -    LLModelLoader::texture_load_func_t  texture_load_func, -    LLModelLoader::state_callback_t     state_cb, -    void *                              opaque_userdata, -    JointTransformMap &                 jointTransformMap, -    JointNameSet &                      jointsFromNodes, -    std::map<std::string, std::string> &jointAliasMap, -    U32                                 maxJointsPerMesh, -    U32                                 modelLimit, -    std::vector<LLJointData>            viewer_skeleton) //, -    //bool                                preprocess) -    : LLModelLoader( filename, -                     lod, -                     load_cb, -                     joint_lookup_func, -                     texture_load_func, -                     state_cb, -                     opaque_userdata, -                     jointTransformMap, -                     jointsFromNodes, -                     jointAliasMap, -                     maxJointsPerMesh ) -    , mGeneratedModelLimit(modelLimit) -    , mViewerJointData(viewer_skeleton) -{ -} - -LLGLTFLoader::~LLGLTFLoader() {} - -bool LLGLTFLoader::OpenFile(const std::string &filename) -{ -    tinygltf::TinyGLTF loader; -    std::string filename_lc(filename); -    LLStringUtil::toLower(filename_lc); - -    mGltfLoaded = mGLTFAsset.load(filename, false); - -    if (!mGltfLoaded) -    { -        notifyUnsupportedExtension(true); - -        for (const auto& buffer : mGLTFAsset.mBuffers) -        { -            if (buffer.mByteLength > 0 && buffer.mData.empty()) -            { -                bool bin_file = buffer.mUri.ends_with(".bin"); -                LLSD args; -                args["Message"] = bin_file ? "ParsingErrorMissingBufferBin" : "ParsingErrorMissingBuffer"; -                args["BUFFER_NAME"] = buffer.mName; -                args["BUFFER_URI"] = buffer.mUri; -                mWarningsArray.append(args); -            } -        } -        setLoadState(ERROR_PARSING); -        return false; -    } - -    notifyUnsupportedExtension(false); - -    bool meshesLoaded = parseMeshes(); - -    setLoadState(DONE); - -    return meshesLoaded; -} - -void LLGLTFLoader::addModelToScene( -    LLModel* pModel, -    U32 submodel_limit, -    const LLMatrix4& transformation, -    const LLVolumeParams& volume_params, -    const material_map& mats) -{ -    U32 volume_faces = pModel->getNumVolumeFaces(); - -    // Side-steps all manner of issues when splitting models -    // and matching lower LOD materials to base models -    // -    pModel->sortVolumeFacesByMaterialName(); - -    int submodelID = 0; - -    // remove all faces that definitely won't fit into one model and submodel limit -    U32 face_limit = (submodel_limit + 1) * LL_SCULPT_MESH_MAX_FACES; -    if (face_limit < volume_faces) -    { -        pModel->setNumVolumeFaces(face_limit); -    } - -    LLVolume::face_list_t remainder; -    std::vector<LLModel*> ready_models; -    LLModel* current_model = pModel; -    do -    { -        current_model->trimVolumeFacesToSize(LL_SCULPT_MESH_MAX_FACES, &remainder); - -        volume_faces = static_cast<U32>(remainder.size()); - -        // Don't add to scene yet because weights and materials aren't ready. -        // Just save it -        ready_models.push_back(current_model); - -        // If we have left-over volume faces, create another model -        // to absorb them. -        if (volume_faces) -        { -            LLModel* next = new LLModel(volume_params, 0.f); -            next->ClearFacesAndMaterials(); -            next->mSubmodelID = ++submodelID; -            next->mLabel = pModel->mLabel + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod]; -            next->getVolumeFaces() = remainder; -            next->mNormalizedScale = current_model->mNormalizedScale; -            next->mNormalizedTranslation = current_model->mNormalizedTranslation; -            next->mSkinWeights = current_model->mSkinWeights; -            next->mPosition = current_model->mPosition; - -            const LLMeshSkinInfo& current_skin_info = current_model->mSkinInfo; -            LLMeshSkinInfo& next_skin_info = next->mSkinInfo; -            next_skin_info.mJointNames = current_skin_info.mJointNames; -            next_skin_info.mJointNums = current_skin_info.mJointNums; -            next_skin_info.mBindShapeMatrix = current_skin_info.mBindShapeMatrix; -            next_skin_info.mInvBindMatrix = current_skin_info.mInvBindMatrix; -            next_skin_info.mAlternateBindMatrix = current_skin_info.mAlternateBindMatrix; -            next_skin_info.mPelvisOffset = current_skin_info.mPelvisOffset; - - -            if (current_model->mMaterialList.size() > LL_SCULPT_MESH_MAX_FACES) -            { -                next->mMaterialList.assign(current_model->mMaterialList.begin() + LL_SCULPT_MESH_MAX_FACES, current_model->mMaterialList.end()); -                current_model->mMaterialList.resize(LL_SCULPT_MESH_MAX_FACES); -            } - -            current_model = next; -        } - -        remainder.clear(); - -    } while (volume_faces); - -    for (auto model : ready_models) -    { -        // remove unused/redundant vertices -        model->remapVolumeFaces(); - -        mModelList.push_back(model); - -        std::map<std::string, LLImportMaterial> materials; -        for (U32 i = 0; i < (U32)model->mMaterialList.size(); ++i) -        { -            material_map::const_iterator found = mats.find(model->mMaterialList[i]); -            if (found != mats.end()) -            { -                materials[model->mMaterialList[i]] = found->second; -            } -            else -            { -                materials[model->mMaterialList[i]] = LLImportMaterial(); -            } -        } -        mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); -        stretch_extents(model, transformation); -    } -} - -bool LLGLTFLoader::parseMeshes() -{ -    if (!mGltfLoaded) return false; - -    // 2022-04 DJH Volume params from dae example. TODO understand PCODE -    LLVolumeParams volume_params; -    volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - -    mTransform.setIdentity(); - -    for (auto& node : mGLTFAsset.mNodes) -    { -        // Make node matrix valid for correct transformation -        node.makeMatrixValid(); -    } - -    if (mGLTFAsset.mSkins.size() > 0) -    { -        checkForXYrotation(mGLTFAsset.mSkins[0]); -        populateJointGroups(); -    } - -    // Populate the joints from skins first. -    // There's not many skins - and you can pretty easily iterate through the nodes from that. -    for (S32 i = 0; i < mGLTFAsset.mSkins.size(); i++) -    { -        populateJointsFromSkin(i); -    } - -    // Track how many times each mesh name has been used -    std::map<std::string, S32> mesh_name_counts; -    U32 submodel_limit = mGLTFAsset.mNodes.size() > 0 ? mGeneratedModelLimit / (U32)mGLTFAsset.mNodes.size() : 0; - -    // Check if we have scenes defined -    if (!mGLTFAsset.mScenes.empty()) -    { -        // Process the default scene (or first scene if no default) -        S32 scene_idx = mGLTFAsset.mScene >= 0 ? mGLTFAsset.mScene : 0; - -        if (scene_idx < mGLTFAsset.mScenes.size()) -        { -            const LL::GLTF::Scene& scene = mGLTFAsset.mScenes[scene_idx]; - -            LL_INFOS("GLTF_IMPORT") << "Processing scene " << scene_idx << " with " << scene.mNodes.size() << " root nodes" << LL_ENDL; - -            // Process all root nodes defined in the scene -            for (S32 root_idx : scene.mNodes) -            { -                if (root_idx >= 0 && root_idx < static_cast<S32>(mGLTFAsset.mNodes.size())) -                { -                    processNodeHierarchy(root_idx, mesh_name_counts, submodel_limit, volume_params); -                } -            } -        } -    } -    else -    { -        LL_WARNS("GLTF_IMPORT") << "No scenes defined in GLTF file" << LL_ENDL; - -        LLSD args; -        args["Message"] = "NoScenesFound"; -        mWarningsArray.append(args); -        return false; -    } - -    // Check total model count against limit -    U32 total_models = static_cast<U32>(mModelList.size()); -    if (total_models > mGeneratedModelLimit) -    { -        LL_WARNS("GLTF_IMPORT") << "Model contains " << total_models -                                << " mesh parts, exceeding the limit of " << mGeneratedModelLimit << LL_ENDL; - -        LLSD args; -        args["Message"] = "TooManyMeshParts"; -        args["PART_COUNT"] = static_cast<S32>(total_models); -        args["LIMIT"] = static_cast<S32>(mGeneratedModelLimit); -        mWarningsArray.append(args); -        return false; -    } - -    return true; -} - -void LLGLTFLoader::processNodeHierarchy(S32 node_idx, std::map<std::string, S32>& mesh_name_counts, U32 submodel_limit, const LLVolumeParams& volume_params) -{ -    if (node_idx < 0 || node_idx >= static_cast<S32>(mGLTFAsset.mNodes.size())) -        return; - -    auto& node = mGLTFAsset.mNodes[node_idx]; - -    LL_INFOS("GLTF_IMPORT") << "Processing node " << node_idx << " (" << node.mName << ")" -                            << " - has mesh: " << (node.mMesh >= 0 ? "yes" : "no") -                            << " - children: " << node.mChildren.size() << LL_ENDL; - -    // Process this node's mesh if it has one -    if (node.mMesh >= 0 && node.mMesh < mGLTFAsset.mMeshes.size()) -    { -        LLMatrix4    transformation; -        material_map mats; - -        LLModel* pModel = new LLModel(volume_params, 0.f); -        auto& mesh = mGLTFAsset.mMeshes[node.mMesh]; - -        // Get base mesh name and track usage -        std::string base_name = mesh.mName; -        if (base_name.empty()) -        { -            base_name = "mesh_" + std::to_string(node.mMesh); -        } - -        S32 instance_count = mesh_name_counts[base_name]++; - -        if (populateModelFromMesh(pModel, mesh, node, mats, instance_count) && -            (LLModel::NO_ERRORS == pModel->getStatus()) && -            validate_model(pModel)) -        { -            mTransform.setIdentity(); -            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 (node.mSkin >= 0) -            { -                // "Bind Shape Matrix" is supposed to transform the geometry of the skinned mesh -                // into the coordinate space of the joints. -                // In GLTF, this matrix is omitted, and it is assumed that this transform is either -                // premultiplied with the mesh data, or postmultiplied to the inverse bind matrices. -                // -                // TODO: There appears to be missing rotation when joints rotate the model -                // or inverted bind matrices are missing inherited rotation -                // (based of values the 'bento shoes' mesh might be missing 90 degrees horizontaly -                // prior to skinning) - -                pModel->mSkinInfo.mBindShapeMatrix.loadu(mesh_scale); -                LL_INFOS("GLTF_DEBUG") << "Model: " << pModel->mLabel << " mBindShapeMatrix: " << pModel->mSkinInfo.mBindShapeMatrix << LL_ENDL; -            } - -            if (transformation.determinant() < 0) -            { // negative scales are not supported -                LL_INFOS("GLTF_IMPORT") << "Negative scale detected, unsupported post-normalization transform.  domInstance_geometry: " -                           << pModel->mLabel << LL_ENDL; -                LLSD args; -                args["Message"] = "NegativeScaleNormTrans"; -                args["LABEL"]   = pModel->mLabel; -                mWarningsArray.append(args); -            } - -            addModelToScene(pModel, submodel_limit, transformation, volume_params, mats); -            mats.clear(); -        } -        else -        { -            setLoadState(ERROR_MODEL + pModel->getStatus()); -            delete pModel; -            return; -        } -    } -    else if (node.mMesh >= 0) -    { -        // Log invalid mesh reference -        LL_WARNS("GLTF_IMPORT") << "Node " << node_idx << " (" << node.mName -                                << ") references invalid mesh " << node.mMesh -                                << " (total meshes: " << mGLTFAsset.mMeshes.size() << ")" << LL_ENDL; - -        LLSD args; -        args["Message"] = "InvalidMeshReference"; -        args["NODE_NAME"] = node.mName; -        args["MESH_INDEX"] = node.mMesh; -        args["TOTAL_MESHES"] = static_cast<S32>(mGLTFAsset.mMeshes.size()); -        mWarningsArray.append(args); -    } - -    // Process all children recursively -    for (S32 child_idx : node.mChildren) -    { -        processNodeHierarchy(child_idx, mesh_name_counts, submodel_limit, volume_params); -    } -} - -void LLGLTFLoader::computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S32 node_index, glm::mat4& combined_transform) const -{ -    if (node_index < 0 || node_index >= static_cast<S32>(asset.mNodes.size())) -    { -        combined_transform = glm::mat4(1.0f); -        return; -    } - -    const auto& node = asset.mNodes[node_index]; - -    // Ensure the node's matrix is valid -    const_cast<LL::GLTF::Node&>(node).makeMatrixValid(); - -    // Start with this node's transform -    combined_transform = node.mMatrix; - -    // Find and apply parent transform if it exists -    for (size_t i = 0; i < asset.mNodes.size(); ++i) -    { -        const auto& potential_parent = asset.mNodes[i]; -        auto it = std::find(potential_parent.mChildren.begin(), potential_parent.mChildren.end(), node_index); - -        if (it != potential_parent.mChildren.end()) -        { -            // Found parent - recursively get its combined transform and apply it -            glm::mat4 parent_transform; -            computeCombinedNodeTransform(asset, static_cast<S32>(i), parent_transform); -            combined_transform = parent_transform * combined_transform; -            return; // Early exit - a node can only have one parent -        } -    } -} - -bool LLGLTFLoader::addJointToModelSkin(LLMeshSkinInfo& skin_info, S32 gltf_skin_idx, size_t gltf_joint_idx) const -{ -    const std::string& legal_name = mJointNames[gltf_skin_idx][gltf_joint_idx]; -    if (legal_name.empty()) -    { -        llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1 -        return false; -    } -    skin_info.mJointNames.push_back(legal_name); -    skin_info.mJointNums.push_back(-1); - -    // In scope of same skin multiple meshes reuse same bind matrices -    skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[gltf_skin_idx][gltf_joint_idx]); -    skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[gltf_skin_idx][gltf_joint_idx]); - -    return true; -} - -bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& mesh, const LL::GLTF::Node& nodeno, material_map& mats, S32 instance_count) -{ -    // Set the requested label for the floater display and uploading -    pModel->mRequestedLabel = gDirUtilp->getBaseFileName(mFilename, true); - -    // Create unique model name -    std::string base_name = mesh.mName; -    if (base_name.empty()) -    { -        S32 mesh_index = static_cast<S32>(&mesh - &mGLTFAsset.mMeshes[0]); -        base_name = "mesh_" + std::to_string(mesh_index); -    } - -    LL_INFOS("GLTF_DEBUG") << "Processing model " << base_name << LL_ENDL; - -    if (instance_count > 0) -    { -        pModel->mLabel = base_name + "_copy_" + std::to_string(instance_count); -    } -    else -    { -        pModel->mLabel = base_name; -    } - -    pModel->ClearFacesAndMaterials(); - -    S32 skinIdx = nodeno.mSkin; - -    // Compute final combined transform matrix (hierarchy + coordinate rotation) -    S32 node_index = static_cast<S32>(&nodeno - &mGLTFAsset.mNodes[0]); -    glm::mat4 hierarchy_transform; -    computeCombinedNodeTransform(mGLTFAsset, node_index, hierarchy_transform); - -    // Combine transforms: coordinate rotation applied to hierarchy transform -    glm::mat4 final_transform = coord_system_rotation * hierarchy_transform; -    if (mApplyXYRotation) -    { -        final_transform = coord_system_rotationxy * final_transform; -    } - -    // Check if we have a negative scale (flipped coordinate system) -    bool hasNegativeScale = glm::determinant(final_transform) < 0.0f; - -    // Pre-compute normal transform matrix (transpose of inverse of upper-left 3x3) -    const glm::mat3 normal_transform = glm::transpose(glm::inverse(glm::mat3(final_transform))); - -    // Mark unsuported joints with '-1' so that they won't get added into weights -    // GLTF maps all joints onto all meshes. Gather use count per mesh to cut unused ones. -    std::vector<S32> gltf_joint_index_use; -    if (skinIdx >= 0 && mGLTFAsset.mSkins.size() > skinIdx) -    { -        LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx]; - -        size_t jointCnt = gltf_skin.mJoints.size(); -        gltf_joint_index_use.resize(jointCnt); - -        for (size_t i = 0; i < jointCnt; ++i) -        { -            if (mJointNames[i].empty()) -            { -                // This might need to hold a substitute index -                gltf_joint_index_use[i] = -1; // mark as unsupported -            } -        } -    } - -    for (size_t prim_idx = 0; prim_idx < mesh.mPrimitives.size(); ++prim_idx) -    { -        const LL::GLTF::Primitive& prim = mesh.mPrimitives[prim_idx]; - -        // So primitives already have all of the data we need for a given face in SL land. -        // Primitives may only ever have a single material assigned to them - as the relation is 1:1 in terms of intended draw call -        // count. Just go ahead and populate faces direct from the GLTF primitives here. -Geenz 2025-04-07 -        LLVolumeFace face; -        std::vector<GLTFVertex> vertices; - -        LLImportMaterial impMat; -        impMat.mDiffuseColor = LLColor4::white; // Default color - -        // 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 -                                << " for material: " << material->mName << LL_ENDL; - -                            LLSD args; -                            args["Message"] = "TextureFound"; -                            args["TEXTURE_NAME"] = impMat.mDiffuseMapFilename; -                            args["MATERIAL_NAME"] = material->mName; -                            mWarningsArray.append(args); - -                            // 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 -                            { -                                // Texture will be loaded later through the callback system -                                LL_INFOS("GLTF_IMPORT") << "Texture needs loading: " << 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) -                            std::string temp_filename = extractTextureToTempFile(texIndex, "base_color"); -                            if (!temp_filename.empty()) -                            { -                                impMat.mDiffuseMapFilename = temp_filename; -                                impMat.mDiffuseMapLabel = material->mName.empty() ? temp_filename : material->mName; -                            } -                        } -                    } -                } -            } -        } - -        if (prim.getIndexCount() % 3 != 0) -        { -            LL_WARNS("GLTF_IMPORT") << "Mesh '" << mesh.mName << "' primitive " << prim_idx -                << ": Invalid index count " << prim.getIndexCount() -                << " (not divisible by 3). GLTF files must contain triangulated geometry." << LL_ENDL; - -            LLSD args; -            args["Message"] = "InvalidGeometryNonTriangulated"; -            args["MESH_NAME"] = mesh.mName; -            args["PRIMITIVE_INDEX"] = static_cast<S32>(prim_idx); -            args["INDEX_COUNT"] = static_cast<S32>(prim.getIndexCount()); -            mWarningsArray.append(args); -            return false; // Skip this primitive -        } - -        // Apply the global scale and center offset to all vertices -        for (U32 i = 0; i < prim.getVertexCount(); i++) -        { -            // Use pre-computed final_transform -            glm::vec4 pos(prim.mPositions[i][0], prim.mPositions[i][1], prim.mPositions[i][2], 1.0f); -            glm::vec4 transformed_pos = final_transform * pos; - -            GLTFVertex vert; -            vert.position = glm::vec3(transformed_pos); - -            if (!prim.mNormals.empty()) -            { -                // Use pre-computed normal_transform -                glm::vec3 normal_vec(prim.mNormals[i][0], prim.mNormals[i][1], prim.mNormals[i][2]); -                vert.normal = glm::normalize(normal_transform * normal_vec); -            } -            else -            { -                // Use default normal (pointing up in model space) -                vert.normal = glm::normalize(normal_transform * glm::vec3(0.0f, 0.0f, 1.0f)); -                LL_DEBUGS("GLTF_IMPORT") << "No normals found for primitive, using default normal." << LL_ENDL; -            } - -            vert.uv0 = glm::vec2(prim.mTexCoords0[i][0], -prim.mTexCoords0[i][1]); - -            if (skinIdx >= 0) -            { -                vert.weights = glm::vec4(prim.mWeights[i]); - -                auto accessorIdx = prim.mAttributes.at("JOINTS_0"); -                LL::GLTF::Accessor::ComponentType componentType = LL::GLTF::Accessor::ComponentType::UNSIGNED_BYTE; -                if (accessorIdx >= 0) -                { -                    auto accessor = mGLTFAsset.mAccessors[accessorIdx]; -                    componentType = accessor.mComponentType; -                } - -                // The GLTF spec allows for either an unsigned byte for joint indices, or an unsigned short. -                // Detect and unpack accordingly. -                if (componentType == LL::GLTF::Accessor::ComponentType::UNSIGNED_BYTE) -                { -                    auto ujoint = glm::unpackUint4x8((U32)(prim.mJoints[i] & 0xFFFFFFFF)); -                    vert.joints = glm::u16vec4(ujoint.x, ujoint.y, ujoint.z, ujoint.w); -                } -                else if (componentType == LL::GLTF::Accessor::ComponentType::UNSIGNED_SHORT) -                { -                    vert.joints = glm::unpackUint4x16(prim.mJoints[i]); -                } -                else -                { -                    vert.joints = glm::zero<glm::u16vec4>(); -                    vert.weights = glm::zero<glm::vec4>(); -                } -            } -            vertices.push_back(vert); -        } - -        // Check for empty vertex array before processing -        if (vertices.empty()) -        { -            LL_WARNS("GLTF_IMPORT") << "Empty vertex array for primitive " << prim_idx << " in model " << mesh.mName << LL_ENDL; -            LLSD args; -            args["Message"] = "EmptyVertexArray"; -            args["MESH_NAME"] = mesh.mName; -            args["PRIMITIVE_INDEX"] = static_cast<S32>(prim_idx); -            args["INDEX_COUNT"] = static_cast<S32>(prim.getIndexCount()); -            mWarningsArray.append(args); -            return false; // Skip this primitive -        } - -        std::vector<LLVolumeFace::VertexData> faceVertices; -        glm::vec3 min = glm::vec3(FLT_MAX); -        glm::vec3 max = glm::vec3(-FLT_MAX); - -        for (U32 i = 0; i < vertices.size(); i++) -        { -            LLVolumeFace::VertexData vert; - -            // Update min/max bounds -            if (i == 0) -            { -                min = max = vertices[i].position; -            } -            else -            { -                min.x = std::min(min.x, vertices[i].position.x); -                min.y = std::min(min.y, vertices[i].position.y); -                min.z = std::min(min.z, vertices[i].position.z); -                max.x = std::max(max.x, vertices[i].position.x); -                max.y = std::max(max.y, vertices[i].position.y); -                max.z = std::max(max.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); -            vert.setNormal(normal); -            vert.mTexCoord = LLVector2(vertices[i].uv0.x, vertices[i].uv0.y); -            faceVertices.push_back(vert); - -            if (skinIdx >= 0) -            { -                // create list of weights that influence this vertex -                LLModel::weight_list weight_list; - -                // Drop joints that viewer doesn't support (negative in gltf_joint_index_use_count) -                // don't reindex them yet, more indexes will be removed -                // Also drop joints that have no weight. GLTF stores 4 per vertex, so there might be -                // 'empty' ones -                if (gltf_joint_index_use[vertices[i].joints.x] >= 0 -                    && vertices[i].weights.x > 0.f) -                { -                    weight_list.push_back(LLModel::JointWeight(vertices[i].joints.x, vertices[i].weights.x)); -                    gltf_joint_index_use[vertices[i].joints.x]++; -                } -                if (gltf_joint_index_use[vertices[i].joints.y] >= 0 -                    && vertices[i].weights.y > 0.f) -                { -                    weight_list.push_back(LLModel::JointWeight(vertices[i].joints.y, vertices[i].weights.y)); -                    gltf_joint_index_use[vertices[i].joints.y]++; -                } -                if (gltf_joint_index_use[vertices[i].joints.z] >= 0 -                    && vertices[i].weights.z > 0.f) -                { -                    weight_list.push_back(LLModel::JointWeight(vertices[i].joints.z, vertices[i].weights.z)); -                    gltf_joint_index_use[vertices[i].joints.z]++; -                } -                if (gltf_joint_index_use[vertices[i].joints.w] >= 0 -                    && vertices[i].weights.w > 0.f) -                { -                    weight_list.push_back(LLModel::JointWeight(vertices[i].joints.w, vertices[i].weights.w)); -                    gltf_joint_index_use[vertices[i].joints.w]++; -                } - -                std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - -                std::vector<LLModel::JointWeight> wght; -                F32                               total = 0.f; - -                for (U32 j = 0; j < llmin((U32)4, (U32)weight_list.size()); ++j) -                { -                    // take up to 4 most significant weights -                    // Ported from the DAE loader - however, GLTF right now only supports up to four weights per vertex. -                    wght.push_back(weight_list[j]); -                    total += weight_list[j].mWeight; -                } - -                if (total != 0.f) -                { -                    F32 scale = 1.f / total; -                    if (scale != 1.f) -                    { // normalize weights -                        for (U32 j = 0; j < wght.size(); ++j) -                        { -                            wght[j].mWeight *= scale; -                        } -                    } -                } - -                if (wght.size() > 0) -                { -                    pModel->mSkinWeights[LLVector3(vertices[i].position)] = wght; -                } -            } -        } - -        // 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); -        } -        mats[materialName] = impMat; - -        // Indices handling -        if (faceVertices.size() >= USHRT_MAX) -        { -            // Will have to remap 32 bit indices into 16 bit indices -            // For the sake of simplicity build vector of 32 bit indices first -            std::vector<U32> indices_32; -            for (U32 i = 0; i < prim.getIndexCount(); i += 3) -            { -                // When processing indices, flip winding order if needed -                if (hasNegativeScale) -                { -                    // Flip winding order for negative scale -                    indices_32.push_back(prim.mIndexArray[i]); -                    indices_32.push_back(prim.mIndexArray[i + 2]); // Swap these two -                    indices_32.push_back(prim.mIndexArray[i + 1]); -                } -                else -                { -                    indices_32.push_back(prim.mIndexArray[i]); -                    indices_32.push_back(prim.mIndexArray[i + 1]); -                    indices_32.push_back(prim.mIndexArray[i + 2]); -                } -            } - -            // remap 32 bit into multiple 16 bit ones -            std::vector<U16> indices_16; -            std::vector<S64> vertices_remap; // should it be a point map? -            vertices_remap.resize(faceVertices.size(), -1); -            std::vector<LLVolumeFace::VertexData> face_verts; -            min = glm::vec3(FLT_MAX); -            max = glm::vec3(-FLT_MAX); -            for (size_t idx = 0; idx < indices_32.size(); idx++) -            { -                size_t vert_index = indices_32[idx]; -                if (vertices_remap[vert_index] == -1) -                { -                    // First encounter, add it -                    size_t new_vert_idx = face_verts.size(); -                    vertices_remap[vert_index] = (S64)new_vert_idx; -                    face_verts.push_back(faceVertices[vert_index]); -                    vert_index = new_vert_idx; - -                    // Update min/max bounds -                    const LLVector4a& vec = face_verts[new_vert_idx].getPosition(); -                    if (new_vert_idx == 0) -                    { -                        min.x = vec[0]; -                        min.y = vec[1]; -                        min.z = vec[2]; -                        max = min; -                    } -                    else -                    { -                        min.x = std::min(min.x, vec[0]); -                        min.y = std::min(min.y, vec[1]); -                        min.z = std::min(min.z, vec[2]); -                        max.x = std::max(max.x, vec[0]); -                        max.y = std::max(max.y, vec[1]); -                        max.z = std::max(max.z, vec[2]); -                    } -                } -                else -                { -                    // already in vector, get position -                    vert_index = (size_t)vertices_remap[vert_index]; -                } -                indices_16.push_back((U16)vert_index); - -                if (indices_16.size() % 3 == 0 && face_verts.size() >= 65532) -                { -                    LLVolumeFace face; -                    face.fillFromLegacyData(face_verts, indices_16); -                    face.mExtents[0] = LLVector4a(min.x, min.y, min.z, 0); -                    face.mExtents[1] = LLVector4a(max.x, max.y, max.z, 0); -                    pModel->getVolumeFaces().push_back(face); -                    pModel->getMaterialList().push_back(materialName); - -                    std::fill(vertices_remap.begin(), vertices_remap.end(), -1); -                    indices_16.clear(); -                    face_verts.clear(); - -                    min = glm::vec3(FLT_MAX); -                    max = glm::vec3(-FLT_MAX); -                } -            } -            if (indices_16.size() > 0 && face_verts.size() > 0) -            { -                LLVolumeFace face; -                face.fillFromLegacyData(face_verts, indices_16); -                face.mExtents[0] = LLVector4a(min.x, min.y, min.z, 0); -                face.mExtents[1] = LLVector4a(max.x, max.y, max.z, 0); -                pModel->getVolumeFaces().push_back(face); -                pModel->getMaterialList().push_back(materialName); -            } -        } -        else -        { -            // can use indices directly -            std::vector<U16> indices; -            for (U32 i = 0; i < prim.getIndexCount(); i += 3) -            { -                // When processing indices, flip winding order if needed -                if (hasNegativeScale) -                { -                    // Flip winding order for negative scale -                    indices.push_back(prim.mIndexArray[i]); -                    indices.push_back(prim.mIndexArray[i + 2]); // Swap these two -                    indices.push_back(prim.mIndexArray[i + 1]); -                } -                else -                { -                    indices.push_back(prim.mIndexArray[i]); -                    indices.push_back(prim.mIndexArray[i + 1]); -                    indices.push_back(prim.mIndexArray[i + 2]); -                } -            } - -            face.fillFromLegacyData(faceVertices, indices); -            face.mExtents[0] = LLVector4a(min.x, min.y, min.z, 0); -            face.mExtents[1] = LLVector4a(max.x, max.y, max.z, 0); - -            pModel->getVolumeFaces().push_back(face); -            pModel->getMaterialList().push_back(materialName); -        } -    } - -    // Call normalizeVolumeFacesAndWeights to compute proper extents -    pModel->normalizeVolumeFacesAndWeights(); - -    // Fill joint names, bind matrices and remap weight indices -    if (skinIdx >= 0) -    { -        LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx]; -        LLMeshSkinInfo& skin_info = pModel->mSkinInfo; -        S32 valid_joints_count = mValidJointsCount[skinIdx]; - -        S32 replacement_index = 0; -        std::vector<S32> gltfindex_to_joitindex_map; -        size_t jointCnt = gltf_skin.mJoints.size(); -        gltfindex_to_joitindex_map.resize(jointCnt); - -        if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT) -        { -            std::map<std::string, S32> goup_use_count; -            // Assume that 'Torso' group is always in use since that's what everything else is attached to -            goup_use_count["Torso"] = 1; -            // Note that Collisions and Extra groups are all over the place, might want to include them from the start -            // or add individual when parents are added - -            // Check which groups are in use -            for (size_t i = 0; i < jointCnt; ++i) -            { -                std::string& joint_name = mJointNames[skinIdx][i]; -                if (!joint_name.empty()) -                { -                    if (gltf_joint_index_use[i] > 0) -                    { -                        const JointGroups &group = mJointGroups[joint_name]; -                        // Joint in use, increment it's groups -                        goup_use_count[group.mGroup]++; -                        goup_use_count[group.mParentGroup]++; -                    } -                } -            } - -            // 1. add joints that are in use directly -            for (size_t i = 0; i < jointCnt; ++i) -            { -                // Process joint name and idnex -                S32 joint = gltf_skin.mJoints[i]; -                if (gltf_joint_index_use[i] <= 0) -                { -                    // unsupported (-1) joint, drop it -                    // unused (0) joint, drop it -                    continue; -                } - -                if (addJointToModelSkin(skin_info, skinIdx, i)) -                { -                    gltfindex_to_joitindex_map[i] = replacement_index++; -                } -            } - -            // 2. add joints from groups that this model's joints belong to -            // It's perfectly valid to have more joints than is in use -            // Ex: sandals that make your legs digitigrade despite not skining to -            // knees or the like. -            // Todo: sort and add by usecount -            for (size_t i = 0; i < jointCnt; ++i) -            { -                S32 joint = gltf_skin.mJoints[i]; -                if (gltf_joint_index_use[i] != 0) -                { -                    // this step needs only joints that have zero uses -                    continue; -                } -                if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT) -                { -                    break; -                } -                const std::string& legal_name = mJointNames[skinIdx][i]; -                std::string group_name = mJointGroups[legal_name].mGroup; -                if (goup_use_count[group_name] > 0) -                { -                    if (addJointToModelSkin(skin_info, skinIdx, i)) -                    { -                        gltfindex_to_joitindex_map[i] = replacement_index++; -                    } -                } -            } -        } -        else -        { -            // Less than 110, just add every valid joint -            for (size_t i = 0; i < jointCnt; ++i) -            { -                // Process joint name and idnex -                S32 joint = gltf_skin.mJoints[i]; -                if (gltf_joint_index_use[i] < 0) -                { -                    // unsupported (-1) joint, drop it -                    continue; -                } - -                if (addJointToModelSkin(skin_info, skinIdx, i)) -                { -                    gltfindex_to_joitindex_map[i] = replacement_index++; -                } -            } -        } - -        if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT) -        { -            LL_WARNS("GLTF_IMPORT") << "Too many jonts in " << pModel->mLabel -                << " Count: " << (S32)skin_info.mInvBindMatrix.size() -                << " Limit:" << (S32)LL_MAX_JOINTS_PER_MESH_OBJECT << LL_ENDL; -            LLSD args; -            args["Message"] = "ModelTooManyJoint"; -            args["MODEL_NAME"] = pModel->mLabel; -            args["JOINT_COUNT"] = (S32)skin_info.mInvBindMatrix.size(); -            args["MAX"] = (S32)LL_MAX_JOINTS_PER_MESH_OBJECT; -            mWarningsArray.append(args); -        } - -        // Remap indices for pModel->mSkinWeights -        for (auto& weights : pModel->mSkinWeights) -        { -            for (auto& weight : weights.second) -            { -                weight.mJointIdx = gltfindex_to_joitindex_map[weight.mJointIdx]; -            } -        } -    } - -    return true; -} - -void LLGLTFLoader::populateJointsFromSkin(S32 skin_idx) -{ -    const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx]; - -    LL_INFOS("GLTF_DEBUG") << "populateJointFromSkin: Processing skin " << skin_idx << " with " << skin.mJoints.size() << " joints" << LL_ENDL; - -    if (skin.mInverseBindMatrices > 0 && skin.mJoints.size() != skin.mInverseBindMatricesData.size()) -    { -        LL_INFOS("GLTF_IMPORT") << "Bind matrices count mismatch joints count" << LL_ENDL; -        LLSD args; -        args["Message"] = "InvBindCountMismatch"; -        mWarningsArray.append(args); -    } - -    S32 joint_count = (S32)skin.mJoints.size(); -    S32 inverse_count = (S32)skin.mInverseBindMatricesData.size(); -    if (mInverseBindMatrices.size() <= skin_idx) -    { -        mInverseBindMatrices.resize(skin_idx + 1); -        mAlternateBindMatrices.resize(skin_idx + 1); -        mJointNames.resize(skin_idx + 1); -        mValidJointsCount.resize(skin_idx + 1, 0); -    } - -    // fill up joints related data -    joints_data_map_t joints_data; -    joints_name_to_node_map_t names_to_nodes; -    for (S32 i = 0; i < joint_count; i++) -    { -        S32 joint = skin.mJoints[i]; -        LL::GLTF::Node jointNode = mGLTFAsset.mNodes[joint]; -        JointNodeData& data = joints_data[joint]; -        data.mNodeIdx = joint; -        data.mJointListIdx = i; -        data.mGltfRestMatrix = buildGltfRestMatrix(joint, skin); -        data.mGltfMatrix = jointNode.mMatrix; -        data.mOverrideMatrix = glm::mat4(1.f); - -        if (mJointMap.find(jointNode.mName) != mJointMap.end()) -        { -            data.mName = mJointMap[jointNode.mName]; -            data.mIsValidViewerJoint = true; -            mValidJointsCount[skin_idx]++; -        } -        else -        { -            data.mName = jointNode.mName; -            data.mIsValidViewerJoint = false; -        } -        names_to_nodes[data.mName] = joint; - -        for (S32 child : jointNode.mChildren) -        { -            JointNodeData& child_data = joints_data[child]; -            child_data.mParentNodeIdx = joint; -            child_data.mIsParentValidViewerJoint = data.mIsValidViewerJoint; -        } -    } - -    if (mValidJointsCount[skin_idx] > LL_MAX_JOINTS_PER_MESH_OBJECT) -    { -        LL_WARNS("GLTF_IMPORT") << "Too many jonts, will strip unused joints" -            << " Count: " << mValidJointsCount[skin_idx] -            << " Limit:" << (S32)LL_MAX_JOINTS_PER_MESH_OBJECT << LL_ENDL; - -        LLSD args; -        args["Message"] = "SkinJointsOverLimit"; -        args["SKIN_INDEX"] = (S32)skin_idx; -        args["JOINT_COUNT"] = mValidJointsCount[skin_idx]; -        args["MAX"] = (S32)LL_MAX_JOINTS_PER_MESH_OBJECT; -        mWarningsArray.append(args); -    } - -    // Go over viewer joints and build overrides -    glm::mat4 ident(1.0); -    for (auto &viewer_data : mViewerJointData) -    { -        buildOverrideMatrix(viewer_data, joints_data, names_to_nodes, ident, ident); -    } - -    for (S32 i = 0; i < joint_count; i++) -    { -        S32 joint = skin.mJoints[i]; -        LL::GLTF::Node jointNode = mGLTFAsset.mNodes[joint]; -        std::string legal_name(jointNode.mName); -        bool legal_joint = false; -        if (mJointMap.find(legal_name) != mJointMap.end()) -        { -            legal_name = mJointMap[legal_name]; -            legal_joint = true; -            mJointNames[skin_idx].push_back(legal_name); -        } -        else -        { -            mJointNames[skin_idx].emplace_back(); -        } - -        // Compute bind matrices - -        if (!legal_joint) -        { -            // Add placeholder to not break index. -            // Not going to be used by viewer, will be stripped from skin_info. -            LLMatrix4 gltf_transform; -            gltf_transform.setIdentity(); -            mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform)); -        } -        else if (inverse_count > i) -        { -            // Transalte existing bind matrix to viewer's skeleton -            // todo: probably should be 'to viewer's overriden skeleton' -            glm::mat4 original_bind_matrix = glm::inverse(skin.mInverseBindMatricesData[i]); -            glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix; -            glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(joints_data, joint, legal_name); -            glm::mat4 tranlated_original = skeleton_transform * rotated_original; -            glm::mat4 final_inverse_bind_matrix = glm::inverse(tranlated_original); - -            LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(final_inverse_bind_matrix)); -            LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " Translated val: " << gltf_transform << LL_ENDL; -            mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform)); -        } -        else -        { -            // If bind matrices aren't present (they are optional in gltf), -            // assume an identy matrix -            // todo: find a model with this, might need to use rotated matrix -            glm::mat4 inv_bind(1.0f); -            glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(joints_data, joint, legal_name); -            inv_bind = glm::inverse(skeleton_transform * inv_bind); - -            LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(inv_bind)); -            LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " Generated val: " << gltf_transform << LL_ENDL; -            mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform)); -        } - -        // Compute Alternative matrices also known as overrides -        LLMatrix4 original_joint_transform(glm::value_ptr(joints_data[joint].mOverrideMatrix)); - -        // Viewer seems to care only about translation part, -        // but for parity with collada taking original value -        LLMatrix4 newInverse = LLMatrix4(mInverseBindMatrices[skin_idx].back().getF32ptr()); -        newInverse.setTranslation(original_joint_transform.getTranslation()); - -        LL_INFOS("GLTF_DEBUG") << "mAlternateBindMatrix name: " << legal_name << " val: " << newInverse << LL_ENDL; -        mAlternateBindMatrices[skin_idx].push_back(LLMatrix4a(newInverse)); - -        if (legal_joint) -        { -            // Might be needed for uploader UI to correctly identify overriden joints -            // but going to be incorrect if multiple skins are present -            mJointList[legal_name] = newInverse; -            mJointsFromNode.push_front(legal_name); -        } -    } -} - -void LLGLTFLoader::populateJointGroups() -{ -    std::string parent; -    for (auto& viewer_data : mViewerJointData) -    { -        buildJointGroup(viewer_data, parent); -    } -} - - -S32 LLGLTFLoader::findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const -{ -    S32 source_joint_node = gltf_skin.mJoints[source_joint]; -    S32 root_node = source_joint_node; -    S32 found_node = source_joint_node; -    S32 size = (S32)gltf_skin.mJoints.size(); -    do -    { -        root_node = found_node; -        for (S32 i = 0; i < size; i++) -        { -            S32 joint = gltf_skin.mJoints[i]; -            const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint]; -            std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node); -            if (it != jointNode.mChildren.end()) -            { -                // Found node's parent -                found_node = joint; -                if (mJointMap.find(jointNode.mName) != mJointMap.end()) -                { -                    return i; -                } -                break; -            } -        } -    } while (root_node != found_node); - -    return -1; -} - -S32 LLGLTFLoader::findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const -{ -    S32 root_node = 0; -    S32 found_node = source_joint_node; -    S32 size = (S32)gltf_skin.mJoints.size(); -    do -    { -        root_node = found_node; -        for (S32 i = 0; i < size; i++) -        { -            S32 joint = gltf_skin.mJoints[i]; -            const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint]; - -            if (mJointMap.find(jointNode.mName) != mJointMap.end()) -            { -                std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node); -                if (it != jointNode.mChildren.end()) -                { -                    // Found node's parent -                    found_node = joint; -                    break; -                } -            } -        } -    } while (root_node != found_node); - -    return root_node; -} - -S32 LLGLTFLoader::findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const -{ -    S32 root_node = 0; -    S32 found_node = 0; -    S32 size = (S32)gltf_skin.mJoints.size(); -    do -    { -        root_node = found_node; -        for (S32 i = 0; i < size; i++) -        { -            S32 joint = gltf_skin.mJoints[i]; -            const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint]; -            std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node); -            if (it != jointNode.mChildren.end()) -            { -                // Found node's parent -                found_node = joint; -                break; -            } -        } -    } while (root_node != found_node); - -    LL_INFOS("GLTF_DEBUG") << "mJointList name: "; -    const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[root_node]; -    LL_CONT << jointNode.mName << " index: " << root_node << LL_ENDL; -    return root_node; -} - -S32 LLGLTFLoader::findParentNode(S32 node) const -{ -    S32 size = (S32)mGLTFAsset.mNodes.size(); -    for (S32 i = 0; i < size; i++) -    { -        const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[i]; -        std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), node); -        if (it != jointNode.mChildren.end()) -        { -            return i; -        } -    } -    return -1; -} - -void LLGLTFLoader::buildJointGroup(LLJointData& viewer_data, const std::string &parent_group) -{ -    JointGroups& jount_group_data = mJointGroups[viewer_data.mName]; -    jount_group_data.mGroup = viewer_data.mGroup; -    jount_group_data.mParentGroup = parent_group; - -    for (LLJointData& child_data : viewer_data.mChildren) -    { -        buildJointGroup(child_data, viewer_data.mGroup); -    } -} - -void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& parent_support_rest) const -{ -    glm::mat4 new_lefover(1.f); -    glm::mat4 rest(1.f); -    joints_name_to_node_map_t::iterator found_node = names_to_nodes.find(viewer_data.mName); -    if (found_node != names_to_nodes.end()) -    { -        S32 gltf_node_idx = found_node->second; -        JointNodeData& node = gltf_nodes[gltf_node_idx]; -        node.mIsOverrideValid = true; -        node.mViewerRestMatrix = viewer_data.mRestMatrix; - -        glm::mat4 gltf_joint_rest_pose = coord_system_rotation * node.mGltfRestMatrix; -        if (mApplyXYRotation) -        { -            gltf_joint_rest_pose = coord_system_rotationxy * gltf_joint_rest_pose; -        } - -        glm::mat4 translated_joint; -        // Example: -        // Viewer has pelvis->spine1->spine2->torso. -        // gltf example model has pelvis->torso -        // By doing glm::inverse(transalted_rest_spine2) * gltf_rest_torso -        // We get what torso would have looked like if gltf had a spine2 -        if (viewer_data.mIsJoint) -        { -            translated_joint = glm::inverse(parent_rest) * gltf_joint_rest_pose; -        } -        else -        { -            translated_joint = glm::inverse(parent_support_rest) * gltf_joint_rest_pose; -        } - -        glm::vec3 translation_override; -        glm::vec3 skew; -        glm::vec3 scale; -        glm::vec4 perspective; -        glm::quat rotation; -        glm::decompose(translated_joint, scale, rotation, translation_override, skew, perspective); - -        node.mOverrideMatrix = glm::recompose(glm::vec3(1, 1, 1), glm::identity<glm::quat>(), translation_override, glm::vec3(0, 0, 0), glm::vec4(0, 0, 0, 1)); - -        glm::mat4 override_joint = node.mOverrideMatrix; -        override_joint = glm::scale(override_joint, viewer_data.mScale); - -        rest = parent_rest * override_joint; -        node.mOverrideRestMatrix = rest; -    } -    else -    { -        // No override for this joint -        rest = parent_rest * viewer_data.mJointMatrix; -    } - -    glm::mat4 support_rest(1.f); -    if (viewer_data.mSupport == LLJointData::SUPPORT_BASE) -    { -        support_rest = rest; -    } -    else -    { -        support_rest = parent_support_rest; -    } - -    for (LLJointData& child_data : viewer_data.mChildren) -    { -        buildOverrideMatrix(child_data, gltf_nodes, names_to_nodes, rest, support_rest); -    } -} - -glm::mat4 LLGLTFLoader::buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF::Skin& gltf_skin) const -{ -    // This is inefficient since we are recalculating some joints multiple times over -    // Todo: cache it? - -    if (joint_node_index < 0 || joint_node_index >= static_cast<S32>(mGLTFAsset.mNodes.size())) -    { -        return glm::mat4(1.0f); -    } - -    const auto& node = mGLTFAsset.mNodes[joint_node_index]; - -    // Find and apply parent transform if it exists -    for (size_t i = 0; i < mGLTFAsset.mNodes.size(); ++i) -    { -        const auto& potential_parent = mGLTFAsset.mNodes[i]; -        auto it = std::find(potential_parent.mChildren.begin(), potential_parent.mChildren.end(), joint_node_index); - -        if (it != potential_parent.mChildren.end()) -        { -            // Found parent -            if (std::find(gltf_skin.mJoints.begin(), gltf_skin.mJoints.end(), joint_node_index) != gltf_skin.mJoints.end()) -            { -                // parent is a joint - recursively combine transform -                // assumes that matrix is already valid -                return buildGltfRestMatrix(static_cast<S32>(i), gltf_skin) * node.mMatrix; -            } -        } -    } -    // Should we return armature or stop earlier? -    return node.mMatrix; -} - -glm::mat4 LLGLTFLoader::buildGltfRestMatrix(S32 joint_node_index, const joints_data_map_t& joint_data) const -{ -    // This is inefficient since we are recalculating some joints multiple times over -    // Todo: cache it? - -    if (joint_node_index < 0 || joint_node_index >= static_cast<S32>(mGLTFAsset.mNodes.size())) -    { -        return glm::mat4(1.0f); -    } - -    auto& data = joint_data.at(joint_node_index); - -    if (data.mParentNodeIdx >=0) -    { -        return buildGltfRestMatrix(data.mParentNodeIdx, joint_data) * data.mGltfMatrix; -    } -    // Should we return armature or stop earlier? -    return data.mGltfMatrix; -} - -// This function computes the transformation matrix needed to convert from GLTF skeleton space -// to viewer skeleton space for a specific joint - -glm::mat4 LLGLTFLoader::computeGltfToViewerSkeletonTransform(const joints_data_map_t& joints_data_map, S32 gltf_node_index, const std::string& joint_name) const -{ -    const JointNodeData& node_data = joints_data_map.at(gltf_node_index); -    if (!node_data.mIsOverrideValid) -    { -        // For now assume they are identical and return an identity (for ease of debuging) -        return glm::mat4(1.0f); -    } - -    // Get the GLTF joint's rest pose (in GLTF coordinate system) -    const glm::mat4 &gltf_joint_rest_pose = node_data.mGltfRestMatrix; -    glm::mat4 rest_pose = coord_system_rotation * gltf_joint_rest_pose; - -    LL_INFOS("GLTF_DEBUG") << "rest matrix for joint " << joint_name << ": "; - -    LLMatrix4 transform(glm::value_ptr(rest_pose)); - -    LL_CONT << transform << LL_ENDL; - -    // Compute transformation from GLTF space to viewer space -    // This assumes both skeletons are in rest pose initially -    return node_data.mOverrideRestMatrix * glm::inverse(rest_pose); -} - -bool LLGLTFLoader::checkForXYrotation(const LL::GLTF::Skin& gltf_skin, S32 joint_idx, S32 bind_indx) -{ -    glm::mat4 gltf_joint_rest = buildGltfRestMatrix(joint_idx, gltf_skin); -    glm::mat4 test_mat = glm::inverse(gltf_joint_rest) * gltf_skin.mInverseBindMatricesData[bind_indx]; -    // Normally for shoulders it should be something close to -    // {1,0,0,0;0,-1,0,0;0,0,-1,0;0,0,0,1} -    // rotated one will look like -    // {0,0,0,-1;1,0,0,0;0,-1,0,0;0,0,0,1} -    // Todo: This is a cheap hack, -    // figure out how rotation is supposed to work -    return abs(test_mat[0][0]) < 0.5 && abs(test_mat[1][1]) < 0.5 && abs(test_mat[2][2]) < 0.5; -} - -void LLGLTFLoader::checkForXYrotation(const LL::GLTF::Skin& gltf_skin) -{ -    // HACK: figure out model's rotation from shoulders' matrix. -    // This is wrong on many levels: -    // Too limited (only models that have shoulders), -    // Will not work well with things that emulate 3 hands in some manner -    // Only supports xy 90 degree rotation -    // Todo: figure out how to find skeleton's orientation Correctly -    // when model is rotated at a triangle level -    constexpr char right_shoulder_str[] = "mShoulderRight"; -    constexpr char left_shoulder_str[] = "mShoulderLeft"; - -    S32 size = (S32)gltf_skin.mJoints.size(); -    S32 joints_found = 0; -    for (S32 i= 0; i < size; i++) -    { -        S32 joint = gltf_skin.mJoints[i]; -        auto joint_node = mGLTFAsset.mNodes[joint]; - -        // todo: we are doing this search thing everywhere, -        // just pre-translate every joint -        JointMap::iterator found = mJointMap.find(joint_node.mName); -        if (found == mJointMap.end()) -        { -            // unsupported joint -            continue; -        } -        if (found->second == right_shoulder_str || found->second == left_shoulder_str) -        { -            if (checkForXYrotation(gltf_skin, joint, i)) -            { -                joints_found++; -            } -            else -            { -                return; -            } -        } -    } - -    if (joints_found == 2) -    { -        // Both joints in a weird position/rotation, assume rotated model -        mApplyXYRotation = true; -    } -} - -std::string LLGLTFLoader::extractTextureToTempFile(S32 textureIndex, const std::string& texture_type) -{ -    if (textureIndex < 0 || textureIndex >= mGLTFAsset.mTextures.size()) -        return ""; - -    S32 sourceIndex = mGLTFAsset.mTextures[textureIndex].mSource; -    if (sourceIndex < 0 || sourceIndex >= mGLTFAsset.mImages.size()) -        return ""; - -    LL::GLTF::Image& image = mGLTFAsset.mImages[sourceIndex]; - -    // Handle URI-based textures -    if (!image.mUri.empty()) -    { -        return image.mUri; // Return URI directly -    } - -    // Handle embedded textures -    if (image.mBufferView >= 0) -    { -        if (image.mBufferView < mGLTFAsset.mBufferViews.size()) -        { -            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_" + texture_type + "_" + 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(); - -                        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 ""; -} - -void LLGLTFLoader::notifyUnsupportedExtension(bool unsupported) -{ -    std::vector<std::string> extensions = unsupported ? mGLTFAsset.mUnsupportedExtensions : mGLTFAsset.mIgnoredExtensions; -    if (extensions.size() > 0) -    { -        LLSD args; -        args["Message"] = unsupported ? "UnsupportedExtension" : "IgnoredExtension"; -        std::string del; -        std::string ext; -        for (auto& extension : extensions) -        { -            ext += del; -            ext += extension; -            del = ","; -        } -        args["EXT"] = ext; -        mWarningsArray.append(args); -    } -} - diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h deleted file mode 100644 index 048f7df7f5..0000000000 --- a/indra/newview/gltf/llgltfloader.h +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @file LLGLTFLoader.h - * @brief LLGLTFLoader class definition - * - * $LicenseInfo:firstyear=2022&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2022, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLGLTFLoader_H -#define LL_LLGLTFLoader_H - -#include "tinygltf/tiny_gltf.h" - -#include "asset.h" - -#include "llglheaders.h" -#include "lljointdata.h" -#include "llmodelloader.h" - -class LLGLTFLoader : public LLModelLoader -{ -  public: -    typedef std::map<std::string, LLImportMaterial> material_map; -    typedef std::map<std::string, std::string> joint_viewer_parent_map_t; -    typedef std::map<std::string, glm::mat4> joint_viewer_rest_map_t; -    typedef std::map<S32, glm::mat4> joint_node_mat4_map_t; - -    struct JointNodeData -    { -        JointNodeData() -            : mJointListIdx(-1) -            , mNodeIdx(-1) -            , mParentNodeIdx(-1) -            , mIsValidViewerJoint(false) -            , mIsParentValidViewerJoint(false) -            , mIsOverrideValid(false) -        { - -        } -        S32 mJointListIdx; -        S32 mNodeIdx; -        S32 mParentNodeIdx; -        glm::mat4 mGltfRestMatrix; -        glm::mat4 mViewerRestMatrix; -        glm::mat4 mOverrideRestMatrix; -        glm::mat4 mGltfMatrix; -        glm::mat4 mOverrideMatrix; -        std::string mName; -        bool mIsValidViewerJoint; -        bool mIsParentValidViewerJoint; -        bool mIsOverrideValid; -    }; -    typedef std::map <S32, JointNodeData> joints_data_map_t; -    typedef std::map <std::string, S32> joints_name_to_node_map_t; - -    LLGLTFLoader(std::string filename, -                    S32                                 lod, -                    LLModelLoader::load_callback_t      load_cb, -                    LLModelLoader::joint_lookup_func_t  joint_lookup_func, -                    LLModelLoader::texture_load_func_t  texture_load_func, -                    LLModelLoader::state_callback_t     state_cb, -                    void *                              opaque_userdata, -                    JointTransformMap &                 jointTransformMap, -                    JointNameSet &                      jointsFromNodes, -                    std::map<std::string, std::string> &jointAliasMap, -                    U32                                 maxJointsPerMesh, -                    U32                                 modelLimit, -                    std::vector<LLJointData>            viewer_skeleton); //, -                    //bool                                preprocess ); -    virtual ~LLGLTFLoader(); - -    virtual bool OpenFile(const std::string &filename); - -    struct GLTFVertex -    { -        glm::vec3 position; -        glm::vec3 normal; -        glm::vec2 uv0; -        glm::u16vec4 joints; -        glm::vec4 weights; -    }; - -protected: -    LL::GLTF::Asset mGLTFAsset; -    tinygltf::Model mGltfModel; -    bool            mGltfLoaded; -    bool            mApplyXYRotation = false; -    U32             mGeneratedModelLimit; - -    // GLTF isn't aware of viewer's skeleton and uses it's own, -    // so need to take viewer's joints and use them to -    // recalculate iverse bind matrices -    std::vector<LLJointData>             mViewerJointData; - -    // vector of vectors because of a posibility of having more than one skin -    typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t; -    typedef std::vector<std::vector<std::string> > joint_names_t; -    bind_matrices_t                     mInverseBindMatrices; -    bind_matrices_t                     mAlternateBindMatrices; -    joint_names_t                       mJointNames; // empty string when no legal name for a given idx - -    // what group a joint belongs to. -    // For purpose of stripping unused groups when joints are over limit. -    struct JointGroups -    { -        std::string mGroup; -        std::string mParentGroup; -    }; -    typedef std::map<std::string, JointGroups> joint_to_group_map_t; -    joint_to_group_map_t mJointGroups; - -    // per skin joint count, needs to be tracked for the sake of limits check. -    std::vector<S32>                    mValidJointsCount; - -private: -    bool parseMeshes(); -    void computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S32 node_index, glm::mat4& combined_transform) const; -    void processNodeHierarchy(S32 node_idx, std::map<std::string, S32>& mesh_name_counts, U32 submodel_limit, const LLVolumeParams& volume_params); -    bool addJointToModelSkin(LLMeshSkinInfo& skin_info, S32 gltf_skin_idx, size_t gltf_joint_idx) const; -    bool populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh &mesh, const LL::GLTF::Node &node, material_map& mats, S32 instance_count); -    void populateJointsFromSkin(S32 skin_idx); -    void populateJointGroups(); -    void addModelToScene(LLModel* pModel, U32 submodel_limit, const LLMatrix4& transformation, const LLVolumeParams& volume_params, const material_map& mats); -    S32 findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const; -    S32 findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const; -    S32 findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const; // if there are multiple roots, gltf stores them under one commor joint -    S32 findParentNode(S32 node) const; -    void buildJointGroup(LLJointData& viewer_data, const std::string& parent_group); -    void buildOverrideMatrix(LLJointData& data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& support_rest) const; -    glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF::Skin& gltf_skin) const; -    glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const joints_data_map_t& joint_data) const; -    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); - -    std::string extractTextureToTempFile(S32 textureIndex, const std::string& texture_type); - -    void notifyUnsupportedExtension(bool unsupported); - -    //    bool mPreprocessGLTF; - -    /*  Below inherited from dae loader - unknown if/how useful here - -    void processElement(gltfElement *element, bool &badElement, GLTF *gltf); -    void processGltfModel(LLModel *model, GLTF *gltf, gltfElement *pRoot, gltfMesh *mesh, gltfSkin *skin); - -    material_map     getMaterials(LLModel *model, gltfInstance_geometry *instance_geo, GLTF *gltf); -    LLImportMaterial profileToMaterial(gltfProfile_COMMON *material, GLTF *gltf); -    LLColor4         getGltfColor(gltfElement *element); - -    gltfElement *getChildFromElement(gltfElement *pElement, std::string const &name); - -    bool isNodeAJoint(gltfNode *pNode); -    void processJointNode(gltfNode *pNode, std::map<std::string, LLMatrix4> &jointTransforms); -    void extractTranslation(gltfTranslate *pTranslate, LLMatrix4 &transform); -    void extractTranslationViaElement(gltfElement *pTranslateElement, LLMatrix4 &transform); -    void extractTranslationViaSID(gltfElement *pElement, LLMatrix4 &transform); -    void buildJointToNodeMappingFromScene(gltfElement *pRoot); -    void processJointToNodeMapping(gltfNode *pNode); -    void processChildJoints(gltfNode *pParentNode); - -    bool verifyCount(int expected, int result); - -    // Verify that a controller matches vertex counts -    bool verifyController(gltfController *pController); - -    static bool addVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh, LLSD &log_msg); -    static bool createVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh); - -    static LLModel *loadModelFromGltfMesh(gltfMesh *mesh); - -    // Loads a mesh breaking it into one or more models as necessary -    // to get around volume face limitations while retaining >8 materials -    // -    bool loadModelsFromGltfMesh(gltfMesh *mesh, std::vector<LLModel *> &models_out, U32 submodel_limit); - -    static std::string getElementLabel(gltfElement *element); -    static size_t      getSuffixPosition(std::string label); -    static std::string getLodlessLabel(gltfElement *element); - -    static std::string preprocessGLTF(std::string filename); -    */ - -}; -#endif  // LL_LLGLTFLLOADER_H diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 3cb5e9a0d7..9faead9533 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -317,7 +317,7 @@ void GLTFSceneManager::load(const std::string& filename)  {      std::shared_ptr<Asset> asset = std::make_shared<Asset>(); -    if (asset->load(filename, true)) +    if (asset->load(filename))      {          gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions          asset->updateTransforms(); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 41e954b7fa..716e6cd9e3 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -59,7 +59,7 @@ LLFilePicker LLFilePicker::sInstance;  #define XML_FILTER L"XML files (*.xml)\0*.xml\0"  #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"  #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" -#define MODEL_FILTER L"Model files (*.dae, *.gltf, *.glb)\0*.dae;*.gltf;*.glb\0" +#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"  #define MATERIAL_FILTER L"GLTF Files (*.gltf; *.glb)\0*.gltf;*.glb\0"  #define HDRI_FILTER L"HDRI Files (*.exr)\0*.exr\0"  #define MATERIAL_TEXTURES_FILTER L"GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.gltf;*.glb;*.tga;*.bmp;*.jpg;*.jpeg;*.png\0" @@ -217,8 +217,6 @@ bool LLFilePicker::setupFilter(ELoadFilter filter)          break;      case FFLOAD_MODEL:          mOFN.lpstrFilter = MODEL_FILTER \ -            COLLADA_FILTER \ -            MATERIAL_FILTER \              L"\0";          break;      case FFLOAD_MATERIAL: @@ -673,8 +671,6 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF          case FFLOAD_HDRI:              allowedv->push_back("exr");          case FFLOAD_MODEL: -            allowedv->push_back("gltf"); -            allowedv->push_back("glb");          case FFLOAD_COLLADA:              allowedv->push_back("dae");              break; diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index b94c31ec04..5ee93be061 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -179,7 +179,7 @@ void LLFloaterBvhPreview::setAnimCallbacks()      getChild<LLUICtrl>("ease_out_time")->setValidateBeforeCommit( boost::bind(&LLFloaterBvhPreview::validateEaseOut, this, _1));  } -std::map <std::string, std::string> LLFloaterBvhPreview::getJointAliases() +std::map<std::string, std::string, std::less<>> LLFloaterBvhPreview::getJointAliases()  {      LLPointer<LLVOAvatar> av = (LLVOAvatar*)mAnimPreview->getDummyAvatar();      return av->getJointAliases(); @@ -252,7 +252,7 @@ bool LLFloaterBvhPreview::postBuild()                  ELoadStatus load_status = E_ST_OK;                  S32 line_number = 0; -                std::map<std::string, std::string> joint_alias_map = getJointAliases(); +                auto joint_alias_map = getJointAliases();                  loaderp = new LLBVHLoader(file_buffer, load_status, line_number, joint_alias_map);                  std::string status = getString(STATUS[load_status]); diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h index ae64521492..bb69ab65ef 100644 --- a/indra/newview/llfloaterbvhpreview.h +++ b/indra/newview/llfloaterbvhpreview.h @@ -108,7 +108,7 @@ public:                                         S32 status, LLExtStat ext_status);  private:      void setAnimCallbacks() ; -    std::map <std::string, std::string> getJointAliases(); +    std::map<std::string, std::string, std::less<>> getJointAliases();  protected: diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 84b9cb18f8..47471edb92 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -64,7 +64,6 @@  #include "llcallbacklist.h"  #include "llviewertexteditor.h"  #include "llviewernetwork.h" -#include "llmaterialeditor.h"  //static @@ -620,9 +619,11 @@ void LLFloaterModelPreview::onJointListSelection()      LLPanel *panel = mTabContainer->getPanelByName("rigging_panel");      LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list");      LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); +    LLScrollListCtrl *joints_scale = panel->getChild<LLScrollListCtrl>("scale_overrides_list");      LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("pos_overrides_descr");      joints_pos->deleteAllItems(); +    joints_scale->deleteAllItems();      LLScrollListItem *selected = joints_list->getFirstSelected();      if (selected) @@ -756,7 +757,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)          mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);          break;      default: -        LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL; +        LL_ERRS() << "Only supposed to be called to generate models, val: " << mode << LL_ENDL;          break;      } @@ -1487,7 +1488,7 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides)      {          // Populate table -        std::map<std::string, std::string> joint_alias_map; +        std::map<std::string, std::string, std::less<>> joint_alias_map;          mModelPreview->getJointAliases(joint_alias_map);          S32 conflicts = 0; diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 378f5fdf91..28160177f6 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -137,8 +137,7 @@ LLFloaterComboOptions* LLFloaterComboOptions::showUI(          {              combo_picker->mComboOptions->addSimpleElement(*iter);          } -        // select 'Bulk Upload All' option -        combo_picker->mComboOptions->selectNthItem((S32)options.size() - 1); +        combo_picker->mComboOptions->selectFirstItem();          combo_picker->openFloater(LLSD(title));          combo_picker->setFocus(true); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index fc0a3ec58f..49c0006f66 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -30,7 +30,7 @@  #include "llmodelloader.h"  #include "lldaeloader.h" -#include "gltf/llgltfloader.h" +#include "llgltfloader.h"  #include "llfloatermodelpreview.h"  #include "llagent.h" @@ -40,7 +40,6 @@  #include "lldrawable.h"  #include "llface.h"  #include "lliconctrl.h" -#include "lljointdata.h"  #include "llmatrix4a.h"  #include "llmeshrepository.h"  #include "llmeshoptimizer.h" @@ -781,7 +780,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable      mLODFile[lod] = filename; -    std::map<std::string, std::string> joint_alias_map; +    std::map<std::string, std::string, std::less<>> joint_alias_map;      getJointAliases(joint_alias_map);      LLHandle<LLModelPreview> preview_handle = getHandle(); @@ -811,9 +810,6 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable      }      else      { -        LLVOAvatar* av = getPreviewAvatar(); -        std::vector<LLJointData> viewer_skeleton; -        av->getJointMatricesAndHierarhy(viewer_skeleton);          mModelLoader = new LLGLTFLoader(              filename,              lod, @@ -826,8 +822,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable              mJointsFromNode,              joint_alias_map,              LLSkinningUtil::getMaxJointCount(), -            gSavedSettings.getU32("ImporterModelLimit"), -            viewer_skeleton); +            gSavedSettings.getU32("ImporterModelLimit"));      }      if (force_disable_slm) @@ -3095,48 +3090,25 @@ void LLModelPreview::lookupLODModelFiles(S32 lod)      S32 next_lod = (lod - 1 >= LLModel::LOD_IMPOSTOR) ? lod - 1 : LLModel::LOD_PHYSICS;      std::string lod_filename = mLODFile[LLModel::LOD_HIGH]; +    std::string ext = ".dae";      std::string lod_filename_lower(lod_filename);      LLStringUtil::toLower(lod_filename_lower); - -    // Check for each supported file extension -    std::vector<std::string> supported_exts = { ".dae", ".gltf", ".glb" }; -    std::string found_ext; -    std::string::size_type ext_pos = std::string::npos; - -    for (const auto& ext : supported_exts) +    std::string::size_type i = lod_filename_lower.rfind(ext); +    if (i != std::string::npos)      { -        std::string::size_type i = lod_filename_lower.rfind(ext); -        if (i != std::string::npos) -        { -            ext_pos = i; -            found_ext = ext; -            break; -        } +        lod_filename.replace(i, lod_filename.size() - ext.size(), getLodSuffix(next_lod) + ext);      } - -    if (ext_pos != std::string::npos) +    if (gDirUtilp->fileExists(lod_filename))      { -        // Replace extension with LOD suffix + original extension -        std::string lod_file_to_check = lod_filename; -        lod_file_to_check.replace(ext_pos, found_ext.size(), getLodSuffix(next_lod) + found_ext); - -        if (gDirUtilp->fileExists(lod_file_to_check)) -        { -            LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; -            if (fmp) -            { -                fmp->setCtrlLoadFromFile(next_lod); -            } -            loadModel(lod_file_to_check, next_lod); -        } -        else +        LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; +        if (fmp)          { -            lookupLODModelFiles(next_lod); +            fmp->setCtrlLoadFromFile(next_lod);          } +        loadModel(lod_filename, next_lod);      }      else      { -        // No recognized extension found, continue with next LOD          lookupLODModelFiles(next_lod);      }  } diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 47f58afa00..cee43f3cff 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -135,12 +135,6 @@ void LLSkinningUtil::initSkinningMatrixPalette(      initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar); -    if (skin->mInvBindMatrix.size() < count ) -    { -        // faulty model? mInvBindMatrix.size() should have matched mJointNames.size() -        return; -    } -      LLMatrix4a world[LL_CHARACTER_MAX_ANIMATED_JOINTS];      for (S32 j = 0; j < count; ++j) @@ -360,8 +354,7 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a                              {                                  rig_info_tab[joint_num].setIsRiggedTo(true); -                                size_t bind_poses_size = skin->mBindPoseMatrix.size(); -                                const LLMatrix4a& mat = bind_poses_size > joint_index ? skin->mBindPoseMatrix[joint_index] : LLMatrix4a::identity(); +                                const LLMatrix4a& mat = skin->mBindPoseMatrix[joint_index];                                  LLVector4a pos_joint_space;                                  mat.affineTransform(pos, pos_joint_space); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index d9a3ec3004..dcba891f9f 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6306,13 +6306,13 @@ const LLUUID& LLVOAvatar::getID() const  // getJoint()  //-----------------------------------------------------------------------------  // RN: avatar joints are multi-rooted to include screen-based attachments -LLJoint *LLVOAvatar::getJoint( const std::string &name ) +LLJoint* LLVOAvatar::getJoint(std::string_view name)  {      joint_map_t::iterator iter = mJointMap.find(name); -    LLJoint* jointp = NULL; +    LLJoint* jointp = nullptr; -    if (iter == mJointMap.end() || iter->second == NULL) +    if (iter == mJointMap.end() || iter->second == nullptr)      {   //search for joint and cache found joint in lookup table          if (mJointAliasMap.empty())          { @@ -6329,7 +6329,7 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )              canonical_name = name;          }          jointp = mRoot->findJoint(canonical_name); -        mJointMap[name] = jointp; +        mJointMap[std::string(name)] = jointp;      }      else      {   //return cached pointer diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index ab27c5752d..9eb8d3f880 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -202,7 +202,7 @@ public:      void                    startDefaultMotions();      void                    dumpAnimationState(); -    virtual LLJoint*        getJoint(const std::string &name); +    virtual LLJoint*        getJoint(std::string_view name);      LLJoint*                getJoint(S32 num);      void                    initAllJoints(); diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 90ff4067f2..ebba9ba291 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -697,17 +697,17 @@ void LLVOAvatarSelf::idleUpdate(LLAgent &agent, const F64 &time)  }  // virtual -LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) +LLJoint* LLVOAvatarSelf::getJoint(std::string_view name)  {      std::lock_guard lock(mJointMapMutex); -    LLJoint *jointp = NULL; +    LLJoint* jointp = nullptr;      jointp = LLVOAvatar::getJoint(name);      if (!jointp && mScreenp)      {          jointp = mScreenp->findJoint(name);          if (jointp)          { -            mJointMap[name] = jointp; +            mJointMap[std::string(name)] = jointp;          }      }      if (jointp && jointp != mScreenp && jointp != mRoot) diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index f9bea41b1d..f7cd974ab0 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -90,7 +90,7 @@ public:      /*virtual*/ bool        hasMotionFromSource(const LLUUID& source_id);      /*virtual*/ void        stopMotionFromSource(const LLUUID& source_id);      /*virtual*/ void        requestStopMotion(LLMotion* motion); -    /*virtual*/ LLJoint*    getJoint(const std::string &name); +    /*virtual*/ LLJoint*    getJoint(std::string_view name);      /*virtual*/ void renderJoints(); 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 f8543ba1aa..90223fcda8 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -14,7 +14,7 @@   legacy_header_height="25">    <string name="status_idle"></string> -  <string name="status_parse_error">Error: Model parsing issue - see log for details.</string> +  <string name="status_parse_error">Error: Dae parsing issue - see log for details.</string>    <string name="status_bind_shape_orientation">Warning: bind shape matrix is not in standard X-forward orientation.</string>    <string name="status_material_mismatch">Error: Material of model is not a subset of reference model.</string>    <string name="status_reading_file">Loading...</string> @@ -45,7 +45,6 @@    <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>    <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string>    <string name="ModelLoaded">Model [MODEL_NAME] loaded</string> -  <string name="InvBindCountMismatch">Bind matrices count mismatch joints count</string>    <string name="IncompleteTC">Texture coordinates data is not complete.</string>    <string name="PositionNaN">Found NaN while loading position data from DAE-Model, invalid model.</string> @@ -62,22 +61,6 @@    <string name="ParsingErrorNoScene">Document has no visual_scene</string>    <string name="ParsingErrorPositionInvalidModel">Unable to process mesh without position data. Invalid model.</string> - <!-- GLTF specific messages --> -  <string name="NoScenesFound">No scenes defined in GLTF file</string> -  <string name="InvalidMeshReference">Node [NODE_NAME] references invalid mesh [MESH_INDEX] (total meshes: [TOTAL_MESHES])</string> -  <string name="InvalidGeometryNonTriangulated">Mesh [MESH_NAME] primitive [PRIMITIVE_INDEX]: Invalid geometry with [INDEX_COUNT] indices (must be triangulated)</string> -  <string name="EmptyVertexArray">Mesh [MESH_NAME] primitive [PRIMITIVE_INDEX]: Empty vertex array</string> -  <string name="ErrorIndexLimit">Unable to process mesh [MESH_NAME] due to 65,534 vertex limit. Vertex count: [VERTEX_COUNT]</string> -  <string name="TextureFound">Found texture: [TEXTURE_NAME] for material: [MATERIAL_NAME]</string> -  <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_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> -  <string name="ParsingErrorMissingBuffer">Buffer is either missing or empty [BUFFER_NAME].</string> -  <string name="ParsingErrorMissingBufferBin">Buffer is either missing or empty. Check presence of [BUFFER_URI] file.</string> -    <panel      follows="top|left"      height="595" @@ -1723,6 +1706,7 @@ Analysed:     height="408"/>    <panel      follows="right|bottom" +    can_resize="false"      height="140"      layout="topleft"      name="right_panel" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 82e77119ab..a51feeb7ab 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -9453,11 +9453,8 @@ Unable to upload texture: '[NAME]'     icon="alertmodal.tga"     name="CannotUploadMaterial"     type="alertmodal"> -Unable to upload material file. The file may be corrupted, in an unsupported format, or contain invalid data. Please check that you're using a valid GLTF/GLB file with proper material definitions. +There was a problem uploading the file      <tag>fail</tag> -    <usetemplate -     name="okbutton" -     yestext="OK"/>    </notification>    <notification | 
