More missing bits
parent
428f2aa84e
commit
99952dc358
|
|
@ -0,0 +1,620 @@
|
|||
/**
|
||||
* @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 "llsdserialize.h"
|
||||
#include "lljoint.h"
|
||||
#include "llcallbacklist.h"
|
||||
|
||||
#include "glh/glh_linear.h"
|
||||
#include "llmatrix4a.h"
|
||||
|
||||
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& jointMap,
|
||||
JointSet& jointsFromNodes )
|
||||
: mJointList( jointMap )
|
||||
, mJointsFromNode( jointsFromNodes )
|
||||
, LLThread("Model Loader")
|
||||
, mFilename(filename)
|
||||
, mLod(lod)
|
||||
, mFirstTransform(TRUE)
|
||||
, mNumOfFetchingTextures(0)
|
||||
, mLoadCallback(load_cb)
|
||||
, mJointLookupFunc(joint_lookup_func)
|
||||
, mTextureLoadFunc(texture_load_func)
|
||||
, mStateCallback(state_cb)
|
||||
, mOpaqueData(opaque_userdata)
|
||||
, mNoNormalize(false)
|
||||
, mNoOptimize(false)
|
||||
{
|
||||
mJointMap["mPelvis"] = "mPelvis";
|
||||
mJointMap["mTorso"] = "mTorso";
|
||||
mJointMap["mChest"] = "mChest";
|
||||
mJointMap["mNeck"] = "mNeck";
|
||||
mJointMap["mHead"] = "mHead";
|
||||
mJointMap["mSkull"] = "mSkull";
|
||||
mJointMap["mEyeRight"] = "mEyeRight";
|
||||
mJointMap["mEyeLeft"] = "mEyeLeft";
|
||||
mJointMap["mCollarLeft"] = "mCollarLeft";
|
||||
mJointMap["mShoulderLeft"] = "mShoulderLeft";
|
||||
mJointMap["mElbowLeft"] = "mElbowLeft";
|
||||
mJointMap["mWristLeft"] = "mWristLeft";
|
||||
mJointMap["mCollarRight"] = "mCollarRight";
|
||||
mJointMap["mShoulderRight"] = "mShoulderRight";
|
||||
mJointMap["mElbowRight"] = "mElbowRight";
|
||||
mJointMap["mWristRight"] = "mWristRight";
|
||||
mJointMap["mHipRight"] = "mHipRight";
|
||||
mJointMap["mKneeRight"] = "mKneeRight";
|
||||
mJointMap["mAnkleRight"] = "mAnkleRight";
|
||||
mJointMap["mFootRight"] = "mFootRight";
|
||||
mJointMap["mToeRight"] = "mToeRight";
|
||||
mJointMap["mHipLeft"] = "mHipLeft";
|
||||
mJointMap["mKneeLeft"] = "mKneeLeft";
|
||||
mJointMap["mAnkleLeft"] = "mAnkleLeft";
|
||||
mJointMap["mFootLeft"] = "mFootLeft";
|
||||
mJointMap["mToeLeft"] = "mToeLeft";
|
||||
|
||||
mJointMap["avatar_mPelvis"] = "mPelvis";
|
||||
mJointMap["avatar_mTorso"] = "mTorso";
|
||||
mJointMap["avatar_mChest"] = "mChest";
|
||||
mJointMap["avatar_mNeck"] = "mNeck";
|
||||
mJointMap["avatar_mHead"] = "mHead";
|
||||
mJointMap["avatar_mSkull"] = "mSkull";
|
||||
mJointMap["avatar_mEyeRight"] = "mEyeRight";
|
||||
mJointMap["avatar_mEyeLeft"] = "mEyeLeft";
|
||||
mJointMap["avatar_mCollarLeft"] = "mCollarLeft";
|
||||
mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft";
|
||||
mJointMap["avatar_mElbowLeft"] = "mElbowLeft";
|
||||
mJointMap["avatar_mWristLeft"] = "mWristLeft";
|
||||
mJointMap["avatar_mCollarRight"] = "mCollarRight";
|
||||
mJointMap["avatar_mShoulderRight"] = "mShoulderRight";
|
||||
mJointMap["avatar_mElbowRight"] = "mElbowRight";
|
||||
mJointMap["avatar_mWristRight"] = "mWristRight";
|
||||
mJointMap["avatar_mHipRight"] = "mHipRight";
|
||||
mJointMap["avatar_mKneeRight"] = "mKneeRight";
|
||||
mJointMap["avatar_mAnkleRight"] = "mAnkleRight";
|
||||
mJointMap["avatar_mFootRight"] = "mFootRight";
|
||||
mJointMap["avatar_mToeRight"] = "mToeRight";
|
||||
mJointMap["avatar_mHipLeft"] = "mHipLeft";
|
||||
mJointMap["avatar_mKneeLeft"] = "mKneeLeft";
|
||||
mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft";
|
||||
mJointMap["avatar_mFootLeft"] = "mFootLeft";
|
||||
mJointMap["avatar_mToeLeft"] = "mToeLeft";
|
||||
|
||||
|
||||
mJointMap["hip"] = "mPelvis";
|
||||
mJointMap["abdomen"] = "mTorso";
|
||||
mJointMap["chest"] = "mChest";
|
||||
mJointMap["neck"] = "mNeck";
|
||||
mJointMap["head"] = "mHead";
|
||||
mJointMap["figureHair"] = "mSkull";
|
||||
mJointMap["lCollar"] = "mCollarLeft";
|
||||
mJointMap["lShldr"] = "mShoulderLeft";
|
||||
mJointMap["lForeArm"] = "mElbowLeft";
|
||||
mJointMap["lHand"] = "mWristLeft";
|
||||
mJointMap["rCollar"] = "mCollarRight";
|
||||
mJointMap["rShldr"] = "mShoulderRight";
|
||||
mJointMap["rForeArm"] = "mElbowRight";
|
||||
mJointMap["rHand"] = "mWristRight";
|
||||
mJointMap["rThigh"] = "mHipRight";
|
||||
mJointMap["rShin"] = "mKneeRight";
|
||||
mJointMap["rFoot"] = "mFootRight";
|
||||
mJointMap["lThigh"] = "mHipLeft";
|
||||
mJointMap["lShin"] = "mKneeLeft";
|
||||
mJointMap["lFoot"] = "mFootLeft";
|
||||
|
||||
//move into joint mapper class
|
||||
//1. joints for joint offset verification
|
||||
mMasterJointList.push_front("mPelvis");
|
||||
mMasterJointList.push_front("mTorso");
|
||||
mMasterJointList.push_front("mChest");
|
||||
mMasterJointList.push_front("mNeck");
|
||||
mMasterJointList.push_front("mHead");
|
||||
mMasterJointList.push_front("mCollarLeft");
|
||||
mMasterJointList.push_front("mShoulderLeft");
|
||||
mMasterJointList.push_front("mElbowLeft");
|
||||
mMasterJointList.push_front("mWristLeft");
|
||||
mMasterJointList.push_front("mCollarRight");
|
||||
mMasterJointList.push_front("mShoulderRight");
|
||||
mMasterJointList.push_front("mElbowRight");
|
||||
mMasterJointList.push_front("mWristRight");
|
||||
mMasterJointList.push_front("mHipRight");
|
||||
mMasterJointList.push_front("mKneeRight");
|
||||
mMasterJointList.push_front("mFootRight");
|
||||
mMasterJointList.push_front("mHipLeft");
|
||||
mMasterJointList.push_front("mKneeLeft");
|
||||
mMasterJointList.push_front("mFootLeft");
|
||||
|
||||
//2. legacy joint list - used to verify rigs that will not be using joint offsets
|
||||
mMasterLegacyJointList.push_front("mPelvis");
|
||||
mMasterLegacyJointList.push_front("mTorso");
|
||||
mMasterLegacyJointList.push_front("mChest");
|
||||
mMasterLegacyJointList.push_front("mNeck");
|
||||
mMasterLegacyJointList.push_front("mHead");
|
||||
mMasterLegacyJointList.push_front("mHipRight");
|
||||
mMasterLegacyJointList.push_front("mKneeRight");
|
||||
mMasterLegacyJointList.push_front("mFootRight");
|
||||
mMasterLegacyJointList.push_front("mHipLeft");
|
||||
mMasterLegacyJointList.push_front("mKneeLeft");
|
||||
mMasterLegacyJointList.push_front("mFootLeft");
|
||||
|
||||
assert_main_thread();
|
||||
sActiveLoaderList.push_back(this) ;
|
||||
}
|
||||
|
||||
LLModelLoader::~LLModelLoader()
|
||||
{
|
||||
assert_main_thread();
|
||||
sActiveLoaderList.remove(this);
|
||||
}
|
||||
|
||||
void LLModelLoader::run()
|
||||
{
|
||||
doLoadModel();
|
||||
doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
|
||||
}
|
||||
|
||||
bool LLModelLoader::doLoadModel()
|
||||
{
|
||||
//first, look for a .slm file of the same name that was modified later
|
||||
//than the .dae
|
||||
|
||||
if (mTrySLM)
|
||||
{
|
||||
std::string filename = mFilename;
|
||||
|
||||
std::string::size_type i = filename.rfind(".");
|
||||
if (i != std::string::npos)
|
||||
{
|
||||
filename.replace(i, filename.size()-1, ".slm");
|
||||
llstat slm_status;
|
||||
if (LLFile::stat(filename, &slm_status) == 0)
|
||||
{ //slm file exists
|
||||
llstat dae_status;
|
||||
if (LLFile::stat(mFilename, &dae_status) != 0 ||
|
||||
dae_status.st_mtime < slm_status.st_mtime)
|
||||
{
|
||||
if (loadFromSLM(filename))
|
||||
{ //slm successfully loaded, if this fails, fall through and
|
||||
//try loading from dae
|
||||
|
||||
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, 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;
|
||||
}
|
||||
|
||||
// Set name.
|
||||
std::string name = data["name"];
|
||||
if (!name.empty())
|
||||
{
|
||||
model[LLModel::LOD_HIGH][0]->mLabel = name;
|
||||
}
|
||||
|
||||
|
||||
//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;
|
||||
|
||||
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;
|
||||
}
|
||||
instance_list[i].mLOD[lod] = model[lod][idx];
|
||||
}
|
||||
}
|
||||
|
||||
if (!instance_list[i].mModel)
|
||||
instance_list[i].mModel = model[LLModel::LOD_HIGH][idx];
|
||||
}
|
||||
|
||||
|
||||
//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()
|
||||
{
|
||||
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 )
|
||||
{
|
||||
critiqueJointToNodeMappingFromScene();
|
||||
|
||||
//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 );
|
||||
bool isRigLegacyOK = isRigLegacy( jointListFromAsset );
|
||||
|
||||
//It's OK that both could end up being true, both default to false
|
||||
if ( isJointPositionUploadOK )
|
||||
{
|
||||
setRigValidForJointPositionUpload( true );
|
||||
}
|
||||
|
||||
if ( isRigLegacyOK)
|
||||
{
|
||||
setLegacyRigValid( true );
|
||||
}
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// critiqueJointToNodeMappingFromScene()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLModelLoader::critiqueJointToNodeMappingFromScene( void )
|
||||
{
|
||||
//Do the actual nodes back the joint listing from the dae?
|
||||
//if yes then this is a fully rigged asset, otherwise it's just a partial rig
|
||||
|
||||
JointSet::iterator jointsFromNodeIt = mJointsFromNode.begin();
|
||||
JointSet::iterator jointsFromNodeEndIt = mJointsFromNode.end();
|
||||
bool result = true;
|
||||
|
||||
if ( !mJointsFromNode.empty() )
|
||||
{
|
||||
for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt )
|
||||
{
|
||||
std::string name = *jointsFromNodeIt;
|
||||
if ( mJointTransformMap.find( name ) != mJointTransformMap.end() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
llinfos<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<llendl;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
//Determines the following use cases for a rig:
|
||||
//1. Full av rig w/1-1 mapping from the scene and joint array
|
||||
//2. Partial rig but w/o parity between the scene and joint array
|
||||
if ( result )
|
||||
{
|
||||
setRigWithSceneParity( true );
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// isRigLegacy()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
|
||||
{
|
||||
//No joints in asset
|
||||
if ( jointListFromAsset.size() == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
JointSet :: const_iterator masterJointIt = mMasterLegacyJointList.begin();
|
||||
JointSet :: const_iterator masterJointEndIt = mMasterLegacyJointList.end();
|
||||
|
||||
std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
|
||||
std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
|
||||
|
||||
for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
|
||||
{
|
||||
result = false;
|
||||
modelJointIt = jointListFromAsset.begin();
|
||||
|
||||
for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
|
||||
{
|
||||
if ( *masterJointIt == *modelJointIt )
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !result )
|
||||
{
|
||||
llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// isRigSuitableForJointPositionUpload()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset )
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
JointSet :: const_iterator masterJointIt = mMasterJointList.begin();
|
||||
JointSet :: const_iterator masterJointEndIt = mMasterJointList.end();
|
||||
|
||||
std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();
|
||||
std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end();
|
||||
|
||||
for ( ;masterJointIt!=masterJointEndIt;++masterJointIt )
|
||||
{
|
||||
result = false;
|
||||
modelJointIt = jointListFromAsset.begin();
|
||||
|
||||
for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt )
|
||||
{
|
||||
if ( *masterJointIt == *modelJointIt )
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !result )
|
||||
{
|
||||
llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//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() ;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
/**
|
||||
* @file llmodelloader.h
|
||||
* @brief LLModelLoader class definition
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLMODELLOADER_H
|
||||
#define LL_LLMODELLOADER_H
|
||||
|
||||
#include "llmodel.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLJoint;
|
||||
|
||||
typedef std::map<std::string, LLMatrix4> JointTransformMap;
|
||||
typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt;
|
||||
typedef std::map<std::string, std::string> JointMap;
|
||||
typedef std::deque<std::string> JointSet;
|
||||
|
||||
const S32 SLM_SUPPORTED_VERSION = 3;
|
||||
const S32 NUM_LOD = 4;
|
||||
|
||||
class LLModelLoader : public LLThread
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||
typedef std::vector<LLPointer<LLModel > > model_list;
|
||||
typedef std::vector<LLModelInstance> model_instance_list;
|
||||
typedef std::map<LLMatrix4, model_instance_list > scene;
|
||||
|
||||
// Callback with loaded model data and loaded LoD
|
||||
//
|
||||
typedef boost::function<void (scene&,model_list&,S32,void*) > load_callback_t;
|
||||
|
||||
// Function to provide joint lookup by name
|
||||
// (within preview avi skeleton, for example)
|
||||
//
|
||||
typedef boost::function<LLJoint* (const std::string&,void*) > joint_lookup_func_t;
|
||||
|
||||
// Func to load and associate material with all it's textures,
|
||||
// returned value is the number of textures loaded
|
||||
// intentionally non-const so func can modify material to
|
||||
// store platform-specific data
|
||||
//
|
||||
typedef boost::function<U32 (LLImportMaterial&,void*) > texture_load_func_t;
|
||||
|
||||
// Callback to inform client of state changes
|
||||
// during loading process (errors will be reported
|
||||
// as state changes here as well)
|
||||
//
|
||||
typedef boost::function<void (U32,void*) > state_callback_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STARTING = 0,
|
||||
READING_FILE,
|
||||
CREATING_FACES,
|
||||
GENERATING_VERTEX_BUFFERS,
|
||||
GENERATING_LOD,
|
||||
DONE,
|
||||
ERROR_PARSING, //basically loading failed
|
||||
ERROR_MATERIALS,
|
||||
ERROR_PASSWORD_REQUIRED,
|
||||
ERROR_NEED_MORE_MEMORY,
|
||||
ERROR_INVALID_FILE,
|
||||
ERROR_LOADER_SETUP,
|
||||
ERROR_INVALID_PARAMETERS,
|
||||
ERROR_OUT_OF_RANGE,
|
||||
ERROR_FILE_VERSION_INVALID
|
||||
} eLoadState;
|
||||
|
||||
U32 mState;
|
||||
std::string mFilename;
|
||||
|
||||
S32 mLod;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
BOOL mFirstTransform;
|
||||
LLVector3 mExtents[2];
|
||||
|
||||
bool mTrySLM;
|
||||
bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info)
|
||||
|
||||
model_list mModelList;
|
||||
scene mScene;
|
||||
|
||||
typedef std::queue<LLPointer<LLModel> > model_queue;
|
||||
|
||||
//queue of models that need a physics rep
|
||||
model_queue mPhysicsQ;
|
||||
|
||||
//map of avatar joints as named in COLLADA assets to internal joint names
|
||||
JointMap mJointMap;
|
||||
JointTransformMap& mJointList;
|
||||
JointSet& mJointsFromNode;
|
||||
|
||||
LLModelLoader(
|
||||
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& jointMap,
|
||||
JointSet& jointsFromNodes);
|
||||
virtual ~LLModelLoader() ;
|
||||
|
||||
virtual void setNoNormalize() { mNoNormalize = true; }
|
||||
virtual void setNoOptimize() { mNoOptimize = true; }
|
||||
|
||||
virtual void run();
|
||||
|
||||
// Will try SLM or derived class OpenFile as appropriate
|
||||
//
|
||||
virtual bool doLoadModel();
|
||||
|
||||
// Derived classes need to provide their parsing of files here
|
||||
//
|
||||
virtual bool OpenFile(const std::string& filename) = 0;
|
||||
|
||||
bool loadFromSLM(const std::string& filename);
|
||||
|
||||
void loadModelCallback();
|
||||
void loadTextures() ; //called in the main thread.
|
||||
void setLoadState(U32 state);
|
||||
|
||||
|
||||
|
||||
S32 mNumOfFetchingTextures ; //updated in the main thread
|
||||
bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread.
|
||||
|
||||
bool verifyCount( int expected, int result );
|
||||
|
||||
//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps)
|
||||
void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
|
||||
void critiqueJointToNodeMappingFromScene( void );
|
||||
|
||||
//Determines if a rig is a legacy from the joint list
|
||||
bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
|
||||
|
||||
//Determines if a rig is suitable for upload
|
||||
bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
|
||||
|
||||
void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; }
|
||||
const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; }
|
||||
|
||||
const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
|
||||
void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
|
||||
|
||||
const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
|
||||
void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// isNodeAJoint()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool isNodeAJoint(const char* name)
|
||||
{
|
||||
return mJointMap.find(name) != mJointMap.end();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
LLModelLoader::load_callback_t mLoadCallback;
|
||||
LLModelLoader::joint_lookup_func_t mJointLookupFunc;
|
||||
LLModelLoader::texture_load_func_t mTextureLoadFunc;
|
||||
LLModelLoader::state_callback_t mStateCallback;
|
||||
void* mOpaqueData;
|
||||
|
||||
bool mRigParityWithScene;
|
||||
bool mRigValidJointUpload;
|
||||
bool mLegacyRigValid;
|
||||
|
||||
bool mNoNormalize;
|
||||
bool mNoOptimize;
|
||||
|
||||
JointSet mMasterJointList;
|
||||
JointSet mMasterLegacyJointList;
|
||||
JointTransformMap mJointTransformMap;
|
||||
|
||||
static std::list<LLModelLoader*> sActiveLoaderList;
|
||||
static bool isAlive(LLModelLoader* loader) ;
|
||||
};
|
||||
class LLMatrix4a;
|
||||
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform);
|
||||
void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform);
|
||||
|
||||
#endif // LL_LLMODELLOADER_H
|
||||
Loading…
Reference in New Issue