summaryrefslogtreecommitdiff
path: root/indra/llprimitive/llmodelloader.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 21:25:21 +0200
committerAndrey Lihatskiy <alihatskiy@productengine.com>2024-05-22 22:40:26 +0300
commite2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch)
tree1bb897489ce524986f6196201c10ac0d8861aa5f /indra/llprimitive/llmodelloader.cpp
parent069ea06848f766466f1a281144c82a0f2bd79f3a (diff)
Fix line endlings
Diffstat (limited to 'indra/llprimitive/llmodelloader.cpp')
-rw-r--r--indra/llprimitive/llmodelloader.cpp1010
1 files changed, 505 insertions, 505 deletions
diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp
index 1e94b5bf92..9a194567d2 100644
--- a/indra/llprimitive/llmodelloader.cpp
+++ b/indra/llprimitive/llmodelloader.cpp
@@ -1,505 +1,505 @@
-/**
- * @file llmodelloader.cpp
- * @brief LLModelLoader class implementation
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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 "llmodelloader.h"
-
-#include "llapp.h"
-#include "llsdserialize.h"
-#include "lljoint.h"
-#include "llcallbacklist.h"
-
-#include "glh/glh_linear.h"
-#include "llmatrix4a.h"
-#include <boost/bind.hpp>
-
-std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
-
-void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
-{
- LLVector4a box[] =
- {
- LLVector4a(-1, 1,-1),
- LLVector4a(-1, 1, 1),
- LLVector4a(-1,-1,-1),
- LLVector4a(-1,-1, 1),
- LLVector4a( 1, 1,-1),
- LLVector4a( 1, 1, 1),
- LLVector4a( 1,-1,-1),
- LLVector4a( 1,-1, 1),
- };
-
- for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
- {
- const LLVolumeFace& face = model->getVolumeFace(j);
-
- LLVector4a center;
- center.setAdd(face.mExtents[0], face.mExtents[1]);
- center.mul(0.5f);
- LLVector4a size;
- size.setSub(face.mExtents[1],face.mExtents[0]);
- size.mul(0.5f);
-
- for (U32 i = 0; i < 8; i++)
- {
- LLVector4a t;
- t.setMul(size, box[i]);
- t.add(center);
-
- LLVector4a v;
-
- mat.affineTransform(t, v);
-
- if (first_transform)
- {
- first_transform = false;
- min = max = v;
- }
- else
- {
- update_min_max(min, max, v);
- }
- }
- }
-}
-
-void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform)
-{
- LLVector4a mina, maxa;
- LLMatrix4a mata;
-
- mata.loadu(mat);
- mina.load3(min.mV);
- maxa.load3(max.mV);
-
- stretch_extents(model, mata, mina, maxa, first_transform);
-
- min.set(mina.getF32ptr());
- max.set(maxa.getF32ptr());
-}
-
-//-----------------------------------------------------------------------------
-// LLModelLoader
-//-----------------------------------------------------------------------------
-LLModelLoader::LLModelLoader(
- std::string filename,
- S32 lod,
- load_callback_t load_cb,
- joint_lookup_func_t joint_lookup_func,
- texture_load_func_t texture_load_func,
- state_callback_t state_cb,
- void* opaque_userdata,
- JointTransformMap& jointTransformMap,
- JointNameSet& jointsFromNodes,
- JointMap& legalJointNamesMap,
- U32 maxJointsPerMesh)
-: mJointList( jointTransformMap )
-, mJointsFromNode( jointsFromNodes )
-, LLThread("Model Loader")
-, mFilename(filename)
-, mLod(lod)
-, mTrySLM(false)
-, mFirstTransform(true)
-, mNumOfFetchingTextures(0)
-, mLoadCallback(load_cb)
-, mJointLookupFunc(joint_lookup_func)
-, mTextureLoadFunc(texture_load_func)
-, mStateCallback(state_cb)
-, mOpaqueData(opaque_userdata)
-, mRigValidJointUpload(true)
-, mLegacyRigFlags(0)
-, mNoNormalize(false)
-, mNoOptimize(false)
-, mCacheOnlyHitIfRigged(false)
-, mMaxJointsPerMesh(maxJointsPerMesh)
-, mJointMap(legalJointNamesMap)
-{
- assert_main_thread();
- sActiveLoaderList.push_back(this) ;
- mWarningsArray = LLSD::emptyArray();
-}
-
-LLModelLoader::~LLModelLoader()
-{
- assert_main_thread();
- sActiveLoaderList.remove(this);
-}
-
-void LLModelLoader::run()
-{
- mWarningsArray.clear();
- doLoadModel();
- doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
-}
-
-// static
-bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::string& slm_filename)
-{
- slm_filename = model_filename;
-
- std::string::size_type i = model_filename.rfind(".");
- if (i != std::string::npos)
- {
- slm_filename.resize(i, '\0');
- slm_filename.append(".slm");
- return true;
- }
- else
- {
- return false;
- }
-}
-
-bool LLModelLoader::doLoadModel()
-{
- //first, look for a .slm file of the same name that was modified later
- //than the specified model file
-
- if (mTrySLM)
- {
- std::string slm_filename;
- if (getSLMFilename(mFilename, slm_filename))
- {
- llstat slm_status;
- if (LLFile::stat(slm_filename, &slm_status) == 0)
- { //slm file exists
- llstat model_file_status;
- if (LLFile::stat(mFilename, &model_file_status) != 0 ||
- model_file_status.st_mtime < slm_status.st_mtime)
- {
- if (loadFromSLM(slm_filename))
- { //slm successfully loaded, if this fails, fall through and
- //try loading from model file
-
- mLod = -1; //successfully loading from an slm implicitly sets all
- //LoDs
- return true;
- }
- }
- }
- }
- }
-
- return OpenFile(mFilename);
-}
-
-void LLModelLoader::setLoadState(U32 state)
-{
- mStateCallback(state, mOpaqueData);
-}
-
-bool LLModelLoader::loadFromSLM(const std::string& filename)
-{
- //only need to populate mScene with data from slm
- llstat stat;
-
- if (LLFile::stat(filename, &stat))
- { //file does not exist
- return false;
- }
-
- S32 file_size = (S32) stat.st_size;
-
- llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
- LLSD data;
- LLSDSerialize::fromBinary(data, ifstream, file_size);
- ifstream.close();
-
- //build model list for each LoD
- model_list model[LLModel::NUM_LODS];
-
- if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
- { //unsupported version
- return false;
- }
-
- LLSD& mesh = data["mesh"];
-
- LLVolumeParams volume_params;
- volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-
- for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
- {
- for (U32 i = 0; i < mesh.size(); ++i)
- {
- std::stringstream str(mesh[i].asString());
- LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
- if (loaded_model->loadModel(str))
- {
- loaded_model->mLocalID = i;
- model[lod].push_back(loaded_model);
-
- if (lod == LLModel::LOD_HIGH)
- {
- if (!loaded_model->mSkinInfo.mJointNames.empty())
- {
- //check to see if rig is valid
- critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
- }
- else if (mCacheOnlyHitIfRigged)
- {
- return false;
- }
- }
- }
- }
- }
-
- if (model[LLModel::LOD_HIGH].empty())
- { //failed to load high lod
- return false;
- }
-
- //load instance list
- model_instance_list instance_list;
-
- LLSD& instance = data["instance"];
-
- for (U32 i = 0; i < instance.size(); ++i)
- {
- //deserialize instance list
- instance_list.push_back(LLModelInstance(instance[i]));
-
- //match up model instance pointers
- S32 idx = instance_list[i].mLocalMeshID;
- std::string instance_label = instance_list[i].mLabel;
-
- for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
- {
- if (!model[lod].empty())
- {
- if (idx >= model[lod].size())
- {
- if (model[lod].size())
- {
- instance_list[i].mLOD[lod] = model[lod][0];
- }
- else
- {
- instance_list[i].mLOD[lod] = NULL;
- }
- continue;
- }
-
- if (model[lod][idx]
- && model[lod][idx]->mLabel.empty()
- && !instance_label.empty())
- {
- // restore model names
- std::string name = instance_label;
- switch (lod)
- {
- case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
- case LLModel::LOD_LOW: name += "_LOD1"; break;
- case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
- case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
- case LLModel::LOD_HIGH: break;
- }
- model[lod][idx]->mLabel = name;
- }
-
- instance_list[i].mLOD[lod] = model[lod][idx];
- }
- }
-
- if (!instance_list[i].mModel)
- instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
- }
-
- // Set name for UI to use
- std::string name = data["name"];
- if (!name.empty())
- {
- model[LLModel::LOD_HIGH][0]->mRequestedLabel = name;
- }
-
-
- //convert instance_list to mScene
- mFirstTransform = true;
- for (U32 i = 0; i < instance_list.size(); ++i)
- {
- LLModelInstance& cur_instance = instance_list[i];
- mScene[cur_instance.mTransform].push_back(cur_instance);
- stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
- }
-
- setLoadState( DONE );
-
- return true;
-}
-
-//static
-bool LLModelLoader::isAlive(LLModelLoader* loader)
-{
- if(!loader)
- {
- return false ;
- }
-
- std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
- for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
-
- return *iter == loader ;
-}
-
-void LLModelLoader::loadModelCallback()
-{
- if (!LLApp::isExiting())
- {
- mLoadCallback(mScene, mModelList, mLod, mOpaqueData);
- }
-
- while (!isStopped())
- { //wait until this thread is stopped before deleting self
- apr_sleep(100);
- }
-
- //double check if "this" is valid before deleting it, in case it is aborted during running.
- if(!isAlive(this))
- {
- return ;
- }
-
- delete this;
-}
-
-//-----------------------------------------------------------------------------
-// critiqueRigForUploadApplicability()
-//-----------------------------------------------------------------------------
-void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
-{
- //Determines the following use cases for a rig:
- //1. It is suitable for upload with skin weights & joint positions, or
- //2. It is suitable for upload as standard av with just skin weights
-
- bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
- U32 legacy_rig_flags = determineRigLegacyFlags( jointListFromAsset );
-
- // It's OK that both could end up being true.
-
- // Both start out as true and are forced to false if any mesh in
- // the model file is not vald by that criterion. Note that a file
- // can contain multiple meshes.
- if ( !isJointPositionUploadOK )
- {
- // This starts out true, becomes false if false for any loaded
- // mesh.
- setRigValidForJointPositionUpload( false );
- }
-
- legacy_rig_flags |= getLegacyRigFlags();
- // This starts as 0, changes if any loaded mesh has issues
- setLegacyRigFlags(legacy_rig_flags);
-
-}
-
-//-----------------------------------------------------------------------------
-// determineRigLegacyFlags()
-//-----------------------------------------------------------------------------
-U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset )
-{
- //No joints in asset
- if ( jointListFromAsset.size() == 0 )
- {
- return false;
- }
-
- // Too many joints in asset
- if (jointListFromAsset.size()>mMaxJointsPerMesh)
- {
- LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL;
- LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL;
- LLSD args;
- args["Message"] = "TooManyJoint";
- args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size());
- args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh);
- mWarningsArray.append(args);
- return LEGACY_RIG_FLAG_TOO_MANY_JOINTS;
- }
-
- // Unknown joints in asset
- S32 unknown_joint_count = 0;
- for (std::vector<std::string>::const_iterator it = jointListFromAsset.begin();
- it != jointListFromAsset.end(); ++it)
- {
- if (mJointMap.find(*it)==mJointMap.end())
- {
- LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL;
- LLSD args;
- args["Message"] = "UnrecognizedJoint";
- args["[NAME]"] = *it;
- mWarningsArray.append(args);
- unknown_joint_count++;
- }
- }
- if (unknown_joint_count>0)
- {
- LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL;
- LLSD args;
- args["Message"] = "UnknownJoints";
- args["[COUNT]"] = LLSD::Integer(unknown_joint_count);
- mWarningsArray.append(args);
- return LEGACY_RIG_FLAG_UNKNOWN_JOINT;
- }
-
- return LEGACY_RIG_OK;
-}
-//-----------------------------------------------------------------------------
-// isRigSuitableForJointPositionUpload()
-//-----------------------------------------------------------------------------
-bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
-{
- return true;
-}
-
-
-//called in the main thread
-void LLModelLoader::loadTextures()
-{
- bool is_paused = isPaused() ;
- pause() ; //pause the loader
-
- for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
- {
- for(U32 i = 0 ; i < iter->second.size(); i++)
- {
- for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
- j != iter->second[i].mMaterial.end(); ++j)
- {
- LLImportMaterial& material = j->second;
-
- if(!material.mDiffuseMapFilename.empty())
- {
- mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);
- }
- }
- }
- }
-
- if(!is_paused)
- {
- unpause() ;
- }
-}
+/**
+ * @file llmodelloader.cpp
+ * @brief LLModelLoader class implementation
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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 "llmodelloader.h"
+
+#include "llapp.h"
+#include "llsdserialize.h"
+#include "lljoint.h"
+#include "llcallbacklist.h"
+
+#include "glh/glh_linear.h"
+#include "llmatrix4a.h"
+#include <boost/bind.hpp>
+
+std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList;
+
+void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, bool& first_transform)
+{
+ LLVector4a box[] =
+ {
+ LLVector4a(-1, 1,-1),
+ LLVector4a(-1, 1, 1),
+ LLVector4a(-1,-1,-1),
+ LLVector4a(-1,-1, 1),
+ LLVector4a( 1, 1,-1),
+ LLVector4a( 1, 1, 1),
+ LLVector4a( 1,-1,-1),
+ LLVector4a( 1,-1, 1),
+ };
+
+ for (S32 j = 0; j < model->getNumVolumeFaces(); ++j)
+ {
+ const LLVolumeFace& face = model->getVolumeFace(j);
+
+ LLVector4a center;
+ center.setAdd(face.mExtents[0], face.mExtents[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(face.mExtents[1],face.mExtents[0]);
+ size.mul(0.5f);
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector4a t;
+ t.setMul(size, box[i]);
+ t.add(center);
+
+ LLVector4a v;
+
+ mat.affineTransform(t, v);
+
+ if (first_transform)
+ {
+ first_transform = false;
+ min = max = v;
+ }
+ else
+ {
+ update_min_max(min, max, v);
+ }
+ }
+ }
+}
+
+void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, bool& first_transform)
+{
+ LLVector4a mina, maxa;
+ LLMatrix4a mata;
+
+ mata.loadu(mat);
+ mina.load3(min.mV);
+ maxa.load3(max.mV);
+
+ stretch_extents(model, mata, mina, maxa, first_transform);
+
+ min.set(mina.getF32ptr());
+ max.set(maxa.getF32ptr());
+}
+
+//-----------------------------------------------------------------------------
+// LLModelLoader
+//-----------------------------------------------------------------------------
+LLModelLoader::LLModelLoader(
+ std::string filename,
+ S32 lod,
+ load_callback_t load_cb,
+ joint_lookup_func_t joint_lookup_func,
+ texture_load_func_t texture_load_func,
+ state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointTransformMap,
+ JointNameSet& jointsFromNodes,
+ JointMap& legalJointNamesMap,
+ U32 maxJointsPerMesh)
+: mJointList( jointTransformMap )
+, mJointsFromNode( jointsFromNodes )
+, LLThread("Model Loader")
+, mFilename(filename)
+, mLod(lod)
+, mTrySLM(false)
+, mFirstTransform(true)
+, mNumOfFetchingTextures(0)
+, mLoadCallback(load_cb)
+, mJointLookupFunc(joint_lookup_func)
+, mTextureLoadFunc(texture_load_func)
+, mStateCallback(state_cb)
+, mOpaqueData(opaque_userdata)
+, mRigValidJointUpload(true)
+, mLegacyRigFlags(0)
+, mNoNormalize(false)
+, mNoOptimize(false)
+, mCacheOnlyHitIfRigged(false)
+, mMaxJointsPerMesh(maxJointsPerMesh)
+, mJointMap(legalJointNamesMap)
+{
+ assert_main_thread();
+ sActiveLoaderList.push_back(this) ;
+ mWarningsArray = LLSD::emptyArray();
+}
+
+LLModelLoader::~LLModelLoader()
+{
+ assert_main_thread();
+ sActiveLoaderList.remove(this);
+}
+
+void LLModelLoader::run()
+{
+ mWarningsArray.clear();
+ doLoadModel();
+ doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
+}
+
+// static
+bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::string& slm_filename)
+{
+ slm_filename = model_filename;
+
+ std::string::size_type i = model_filename.rfind(".");
+ if (i != std::string::npos)
+ {
+ slm_filename.resize(i, '\0');
+ slm_filename.append(".slm");
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool LLModelLoader::doLoadModel()
+{
+ //first, look for a .slm file of the same name that was modified later
+ //than the specified model file
+
+ if (mTrySLM)
+ {
+ std::string slm_filename;
+ if (getSLMFilename(mFilename, slm_filename))
+ {
+ llstat slm_status;
+ if (LLFile::stat(slm_filename, &slm_status) == 0)
+ { //slm file exists
+ llstat model_file_status;
+ if (LLFile::stat(mFilename, &model_file_status) != 0 ||
+ model_file_status.st_mtime < slm_status.st_mtime)
+ {
+ if (loadFromSLM(slm_filename))
+ { //slm successfully loaded, if this fails, fall through and
+ //try loading from model file
+
+ mLod = -1; //successfully loading from an slm implicitly sets all
+ //LoDs
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return OpenFile(mFilename);
+}
+
+void LLModelLoader::setLoadState(U32 state)
+{
+ mStateCallback(state, mOpaqueData);
+}
+
+bool LLModelLoader::loadFromSLM(const std::string& filename)
+{
+ //only need to populate mScene with data from slm
+ llstat stat;
+
+ if (LLFile::stat(filename, &stat))
+ { //file does not exist
+ return false;
+ }
+
+ S32 file_size = (S32) stat.st_size;
+
+ llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary);
+ LLSD data;
+ LLSDSerialize::fromBinary(data, ifstream, file_size);
+ ifstream.close();
+
+ //build model list for each LoD
+ model_list model[LLModel::NUM_LODS];
+
+ if (data["version"].asInteger() != SLM_SUPPORTED_VERSION)
+ { //unsupported version
+ return false;
+ }
+
+ LLSD& mesh = data["mesh"];
+
+ LLVolumeParams volume_params;
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ for (U32 i = 0; i < mesh.size(); ++i)
+ {
+ std::stringstream str(mesh[i].asString());
+ LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
+ if (loaded_model->loadModel(str))
+ {
+ loaded_model->mLocalID = i;
+ model[lod].push_back(loaded_model);
+
+ if (lod == LLModel::LOD_HIGH)
+ {
+ if (!loaded_model->mSkinInfo.mJointNames.empty())
+ {
+ //check to see if rig is valid
+ critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );
+ }
+ else if (mCacheOnlyHitIfRigged)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (model[LLModel::LOD_HIGH].empty())
+ { //failed to load high lod
+ return false;
+ }
+
+ //load instance list
+ model_instance_list instance_list;
+
+ LLSD& instance = data["instance"];
+
+ for (U32 i = 0; i < instance.size(); ++i)
+ {
+ //deserialize instance list
+ instance_list.push_back(LLModelInstance(instance[i]));
+
+ //match up model instance pointers
+ S32 idx = instance_list[i].mLocalMeshID;
+ std::string instance_label = instance_list[i].mLabel;
+
+ for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ if (!model[lod].empty())
+ {
+ if (idx >= model[lod].size())
+ {
+ if (model[lod].size())
+ {
+ instance_list[i].mLOD[lod] = model[lod][0];
+ }
+ else
+ {
+ instance_list[i].mLOD[lod] = NULL;
+ }
+ continue;
+ }
+
+ if (model[lod][idx]
+ && model[lod][idx]->mLabel.empty()
+ && !instance_label.empty())
+ {
+ // restore model names
+ std::string name = instance_label;
+ switch (lod)
+ {
+ case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break;
+ case LLModel::LOD_LOW: name += "_LOD1"; break;
+ case LLModel::LOD_MEDIUM: name += "_LOD2"; break;
+ case LLModel::LOD_PHYSICS: name += "_PHYS"; break;
+ case LLModel::LOD_HIGH: break;
+ }
+ model[lod][idx]->mLabel = name;
+ }
+
+ instance_list[i].mLOD[lod] = model[lod][idx];
+ }
+ }
+
+ if (!instance_list[i].mModel)
+ instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
+ }
+
+ // Set name for UI to use
+ std::string name = data["name"];
+ if (!name.empty())
+ {
+ model[LLModel::LOD_HIGH][0]->mRequestedLabel = name;
+ }
+
+
+ //convert instance_list to mScene
+ mFirstTransform = true;
+ for (U32 i = 0; i < instance_list.size(); ++i)
+ {
+ LLModelInstance& cur_instance = instance_list[i];
+ mScene[cur_instance.mTransform].push_back(cur_instance);
+ stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform);
+ }
+
+ setLoadState( DONE );
+
+ return true;
+}
+
+//static
+bool LLModelLoader::isAlive(LLModelLoader* loader)
+{
+ if(!loader)
+ {
+ return false ;
+ }
+
+ std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ;
+ for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ;
+
+ return *iter == loader ;
+}
+
+void LLModelLoader::loadModelCallback()
+{
+ if (!LLApp::isExiting())
+ {
+ mLoadCallback(mScene, mModelList, mLod, mOpaqueData);
+ }
+
+ while (!isStopped())
+ { //wait until this thread is stopped before deleting self
+ apr_sleep(100);
+ }
+
+ //double check if "this" is valid before deleting it, in case it is aborted during running.
+ if(!isAlive(this))
+ {
+ return ;
+ }
+
+ delete this;
+}
+
+//-----------------------------------------------------------------------------
+// critiqueRigForUploadApplicability()
+//-----------------------------------------------------------------------------
+void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset )
+{
+ //Determines the following use cases for a rig:
+ //1. It is suitable for upload with skin weights & joint positions, or
+ //2. It is suitable for upload as standard av with just skin weights
+
+ bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
+ U32 legacy_rig_flags = determineRigLegacyFlags( jointListFromAsset );
+
+ // It's OK that both could end up being true.
+
+ // Both start out as true and are forced to false if any mesh in
+ // the model file is not vald by that criterion. Note that a file
+ // can contain multiple meshes.
+ if ( !isJointPositionUploadOK )
+ {
+ // This starts out true, becomes false if false for any loaded
+ // mesh.
+ setRigValidForJointPositionUpload( false );
+ }
+
+ legacy_rig_flags |= getLegacyRigFlags();
+ // This starts as 0, changes if any loaded mesh has issues
+ setLegacyRigFlags(legacy_rig_flags);
+
+}
+
+//-----------------------------------------------------------------------------
+// determineRigLegacyFlags()
+//-----------------------------------------------------------------------------
+U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset )
+{
+ //No joints in asset
+ if ( jointListFromAsset.size() == 0 )
+ {
+ return false;
+ }
+
+ // Too many joints in asset
+ if (jointListFromAsset.size()>mMaxJointsPerMesh)
+ {
+ LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL;
+ LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL;
+ LLSD args;
+ args["Message"] = "TooManyJoint";
+ args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size());
+ args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh);
+ mWarningsArray.append(args);
+ return LEGACY_RIG_FLAG_TOO_MANY_JOINTS;
+ }
+
+ // Unknown joints in asset
+ S32 unknown_joint_count = 0;
+ for (std::vector<std::string>::const_iterator it = jointListFromAsset.begin();
+ it != jointListFromAsset.end(); ++it)
+ {
+ if (mJointMap.find(*it)==mJointMap.end())
+ {
+ LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL;
+ LLSD args;
+ args["Message"] = "UnrecognizedJoint";
+ args["[NAME]"] = *it;
+ mWarningsArray.append(args);
+ unknown_joint_count++;
+ }
+ }
+ if (unknown_joint_count>0)
+ {
+ LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL;
+ LLSD args;
+ args["Message"] = "UnknownJoints";
+ args["[COUNT]"] = LLSD::Integer(unknown_joint_count);
+ mWarningsArray.append(args);
+ return LEGACY_RIG_FLAG_UNKNOWN_JOINT;
+ }
+
+ return LEGACY_RIG_OK;
+}
+//-----------------------------------------------------------------------------
+// isRigSuitableForJointPositionUpload()
+//-----------------------------------------------------------------------------
+bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
+{
+ return true;
+}
+
+
+//called in the main thread
+void LLModelLoader::loadTextures()
+{
+ bool is_paused = isPaused() ;
+ pause() ; //pause the loader
+
+ for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter)
+ {
+ for(U32 i = 0 ; i < iter->second.size(); i++)
+ {
+ for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin();
+ j != iter->second[i].mMaterial.end(); ++j)
+ {
+ LLImportMaterial& material = j->second;
+
+ if(!material.mDiffuseMapFilename.empty())
+ {
+ mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);
+ }
+ }
+ }
+ }
+
+ if(!is_paused)
+ {
+ unpause() ;
+ }
+}