summaryrefslogtreecommitdiff
path: root/indra/newview/llfloatermodelpreview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfloatermodelpreview.cpp')
-rwxr-xr-xindra/newview/llfloatermodelpreview.cpp566
1 files changed, 456 insertions, 110 deletions
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index ce977b33bb..a808cc47a2 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -82,6 +82,7 @@
#include "llvoavatarself.h"
#include "pipeline.h"
#include "lluictrlfactory.h"
+#include "llviewercontrol.h"
#include "llviewermenu.h"
#include "llviewermenufile.h"
#include "llviewerregion.h"
@@ -90,6 +91,7 @@
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llradiogroup.h"
+#include "llsdserialize.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
#include "lltoggleablemenu.h"
@@ -109,6 +111,8 @@ const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
const S32 PREVIEW_TEXTURE_HEIGHT = 300;
+const F32 MAXIMUM_PIVOT_OFFSET = 64.0f;
+
void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
@@ -275,11 +279,6 @@ BOOL LLFloaterModelPreview::postBuild()
return FALSE;
}
-
-
-
-
-
childSetAction("lod_browse", onBrowseLOD, this);
childSetCommitCallback("cancel_btn", onCancel, this);
@@ -302,6 +301,8 @@ BOOL LLFloaterModelPreview::postBuild()
childSetAction("ok_btn", onUpload, this);
childDisable("ok_btn");
+ childSetAction("reset_btn", onReset, this);
+
childSetAction("clear_materials", onClearMaterials, this);
childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this);
@@ -320,8 +321,6 @@ BOOL LLFloaterModelPreview::postBuild()
childDisable("upload_skin");
childDisable("upload_joints");
- childDisable("pelvis_offset");
-
childDisable("ok_btn");
mViewOptionMenuButton = getChild<LLMenuButton>("options_gear_btn");
@@ -382,14 +381,17 @@ BOOL LLFloaterModelPreview::postBuild()
LLFloaterModelPreview::~LLFloaterModelPreview()
{
sInstance = NULL;
-
- const LLModelLoader *model_loader = mModelPreview->mModelLoader;
- if (model_loader && model_loader->mResetJoints)
+
+ if ( mModelPreview && mModelPreview->getResetJointFlag() )
{
gAgentAvatarp->resetJointPositions();
}
- delete mModelPreview;
+
+ if ( mModelPreview )
+ {
+ delete mModelPreview;
+ }
if (mGLName)
{
@@ -572,7 +574,14 @@ void LLFloaterModelPreview::draw()
if (!mModelPreview->mLoading)
{
- childSetTextArg("status", "[STATUS]", getString("status_idle"));
+ if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING )
+ {
+ childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING)));
+ }
+ else
+ {
+ childSetTextArg("status", "[STATUS]", getString("status_idle"));
+ }
}
childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost));
@@ -986,7 +995,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
// LLModelLoader
//-----------------------------------------------------------------------------
LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview)
-: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mResetJoints( FALSE )
+: LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE)
{
mJointMap["mPelvis"] = "mPelvis";
mJointMap["mTorso"] = "mTorso";
@@ -1087,8 +1096,15 @@ LLModelLoader::LLModelLoader(std::string filename, S32 lod, LLModelPreview* prev
if (mPreview)
{
+ //only try to load from slm if viewer is configured to do so and this is the
+ //initial model load (not an LoD or physics shape)
+ mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty();
mPreview->setLoadState(STARTING);
}
+ else
+ {
+ mTrySLM = false;
+ }
}
void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform)
@@ -1166,6 +1182,38 @@ void LLModelLoader::run()
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;
+ }
+ }
+ }
+ }
+ }
+
+ //no suitable slm exists, load from the .dae file
DAE dae;
domCOLLADA* dom = dae.open(mFilename);
@@ -1239,6 +1287,12 @@ bool LLModelLoader::doLoadModel()
{
LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh);
+ if(model->getStatus() != LLModel::NO_ERRORS)
+ {
+ setLoadState(ERROR_PARSING + model->getStatus()) ;
+ return true ; //abort
+ }
+
if (model.notNull() && validate_model(model))
{
mModelList.push_back(model);
@@ -1287,17 +1341,19 @@ bool LLModelLoader::doLoadModel()
{ //get bind shape matrix
domFloat4x4& dom_value = bind_mat->getValue();
+ LLMeshSkinInfo& skin_info = model->mSkinInfo;
+
for (int i = 0; i < 4; i++)
{
for(int j = 0; j < 4; j++)
{
- model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+ skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
}
}
LLMatrix4 trans = normalized_transformation;
- trans *= model->mBindShapeMatrix;
- model->mBindShapeMatrix = trans;
+ trans *= skin_info.mBindShapeMatrix;
+ skin_info.mBindShapeMatrix = trans;
}
@@ -1436,7 +1492,7 @@ bool LLModelLoader::doLoadModel()
xsNMTOKEN semantic = input->getSemantic();
if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
- { //found joint source, fill model->mJointMap and model->mJointList
+ { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
daeElement* elem = input->getSource().getElement();
domSource* source = daeSafeCast<domSource>(elem);
@@ -1457,8 +1513,8 @@ bool LLModelLoader::doLoadModel()
{
name = mJointMap[name];
}
- model->mJointList.push_back(name);
- model->mJointMap[name] = j;
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
}
}
else
@@ -1475,8 +1531,8 @@ bool LLModelLoader::doLoadModel()
{
name = mJointMap[name];
}
- model->mJointList.push_back(name);
- model->mJointMap[name] = j;
+ model->mSkinInfo.mJointNames.push_back(name);
+ model->mSkinInfo.mJointMap[name] = j;
}
}
}
@@ -1505,7 +1561,7 @@ bool LLModelLoader::doLoadModel()
}
}
- model->mInvBindMatrix.push_back(mat);
+ model->mSkinInfo.mInvBindMatrix.push_back(mat);
}
}
}
@@ -1516,17 +1572,17 @@ bool LLModelLoader::doLoadModel()
//(which means we have all the joints that are required for an avatar versus
//a skinned asset attached to a node in a file that contains an entire skeleton,
//but does not use the skeleton).
- mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) );
- if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() )
+ mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) );
+ if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() )
{
- mResetJoints = true;
+ mPreview->setResetJointFlag( true );
}
if ( !missingSkeletonOrScene )
{
//Set the joint translations on the avatar - if it's a full mapping
//The joints are reset in the dtor
- if ( mResetJoints )
+ if ( mPreview->getResetJointFlag() )
{
std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin();
std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end();
@@ -1557,8 +1613,8 @@ bool LLModelLoader::doLoadModel()
//in the same order as they were stored in the joint buffer. The joints associated
//with the skeleton are not stored in the same order as they are in the exported joint buffer.
//This remaps the skeletal joints to be in the same order as the joints stored in the model.
- std::vector<std::string> :: const_iterator jointIt = model->mJointList.begin();
- const int jointCnt = model->mJointList.size();
+ std::vector<std::string> :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin();
+ const int jointCnt = model->mSkinInfo.mJointNames.size();
for ( int i=0; i<jointCnt; ++i, ++jointIt )
{
std::string lookingForJoint = (*jointIt).c_str();
@@ -1567,9 +1623,9 @@ bool LLModelLoader::doLoadModel()
if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() )
{
LLMatrix4 jointTransform = jointTransforms[lookingForJoint];
- LLMatrix4 newInverse = model->mInvBindMatrix[i];
+ LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() );
- model->mAlternateBindMatrix.push_back( newInverse );
+ model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
}
else
{
@@ -1743,12 +1799,103 @@ void LLModelLoader::setLoadState(U32 state)
}
}
+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];
+
+ 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 && !loaded_model->mSkinInfo.mJointNames.empty())
+ { //check to see if rig is valid
+ mPreview->setRigValid( doesJointArrayContainACompleteRig( loaded_model->mSkinInfo.mJointNames ) );
+ }
+ }
+ else
+ {
+ llassert(model[lod].empty());
+ }
+ }
+ }
+
+ 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;
+
+ for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ {
+ if (!model[lod].empty())
+ {
+ instance_list[i].mLOD[lod] = model[lod][idx];
+ }
+ }
+
+ 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;
+}
+
void LLModelLoader::loadModelCallback()
{
if (mPreview)
{
- mPreview->loadModelCallback(mLod);
- mPreview->mModelLoader = NULL;
+ mPreview->loadModelCallback(mLod);
}
while (!isStopped())
@@ -1756,6 +1903,12 @@ void LLModelLoader::loadModelCallback()
apr_sleep(100);
}
+ //cleanup model loader
+ if (mPreview)
+ {
+ mPreview->mModelLoader = NULL;
+ }
+
delete this;
}
@@ -1781,8 +1934,19 @@ void LLModelLoader::handlePivotPoint( daeElement* pRoot )
if ( pTranslate )
{
extractTranslation( pTranslate, workingTransform );
- mPreview->setModelPivot( workingTransform.getTranslation() );
- mPreview->setHasPivot( true );
+ LLVector3 pivotTrans = workingTransform.getTranslation();
+ if ( pivotTrans[VX] > MAXIMUM_PIVOT_OFFSET || pivotTrans[VX] < -MAXIMUM_PIVOT_OFFSET ||
+ pivotTrans[VY] > MAXIMUM_PIVOT_OFFSET || pivotTrans[VY] < -MAXIMUM_PIVOT_OFFSET ||
+ pivotTrans[VZ] > MAXIMUM_PIVOT_OFFSET || pivotTrans[VZ] < -MAXIMUM_PIVOT_OFFSET )
+ {
+ llwarns<<"Asset Pivot Node contains an offset that is too large - values should be within (-"<<MAXIMUM_PIVOT_OFFSET<<","<<MAXIMUM_PIVOT_OFFSET<<")."<<llendl;
+ mPreview->setHasPivot( false );
+ }
+ else
+ {
+ mPreview->setModelPivot( pivotTrans );
+ mPreview->setHasPivot( true );
+ }
}
}
}
@@ -2293,6 +2457,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL)
, mPelvisZOffset( 0.0f )
, mRigValid( false )
+, mResetJoints( false )
{
mNeedsUpdate = TRUE;
mCameraDistance = 0.f;
@@ -2332,6 +2497,7 @@ LLModelPreview::~LLModelPreview()
{
if (mModelLoader)
{
+ delete mModelLoader;
mModelLoader->mPreview = NULL;
}
//*HACK : *TODO : turn this back on when we understand why this crashes
@@ -2346,7 +2512,7 @@ U32 LLModelPreview::calcResourceCost()
if (mFMP && mModelLoader)
{
- if ( getLoadState() != LLModelLoader::ERROR_PARSING )
+ if ( getLoadState() < LLModelLoader::ERROR_PARSING )
{
mFMP->childEnable("ok_btn");
}
@@ -2368,8 +2534,13 @@ U32 LLModelPreview::calcResourceCost()
U32 num_hulls = 0;
F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f;
- mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 32.0f;
+ mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f;
+ if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() )
+ {
+ gAgentAvatarp->setPelvisOffset( mPelvisZOffset );
+ }
+
F32 streaming_cost = 0.f;
F32 physics_cost = 0.f;
for (U32 i = 0; i < mUploadData.size(); ++i)
@@ -2380,28 +2551,37 @@ U32 LLModelPreview::calcResourceCost()
{
accounted.insert(instance.mModel);
- LLModel::convex_hull_decomposition& decomp =
+ LLModel::Decomposition& decomp =
instance.mLOD[LLModel::LOD_PHYSICS] ?
- instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp :
- instance.mModel->mConvexHullDecomp;
-
- LLSD ret = LLModel::writeModel(
- "",
- instance.mLOD[4],
- instance.mLOD[3],
- instance.mLOD[2],
- instance.mLOD[1],
- instance.mLOD[0],
- decomp,
- mFMP->childGetValue("upload_skin").asBoolean(),
- mFMP->childGetValue("upload_joints").asBoolean(),
- TRUE);
+ instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
+ instance.mModel->mPhysics;
+
+ //update instance skin info for each lods pelvisZoffset
+ for ( int j=0; j<LLModel::NUM_LODS; ++j )
+ {
+ if ( instance.mLOD[j] )
+ {
+ instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset;
+ }
+ }
+
+ std::stringstream ostr;
+ LLSD ret = LLModel::writeModel(ostr,
+ instance.mLOD[4],
+ instance.mLOD[3],
+ instance.mLOD[2],
+ instance.mLOD[1],
+ instance.mLOD[0],
+ decomp,
+ mFMP->childGetValue("upload_skin").asBoolean(),
+ mFMP->childGetValue("upload_joints").asBoolean(),
+ TRUE);
cost += gMeshRepo.calcResourceCost(ret);
- num_hulls += decomp.size();
- for (U32 i = 0; i < decomp.size(); ++i)
+ num_hulls += decomp.mHull.size();
+ for (U32 i = 0; i < decomp.mHull.size(); ++i)
{
- num_points += decomp[i].size();
+ num_points += decomp.mHull[i].size();
}
//calculate streaming cost
@@ -2561,6 +2741,75 @@ void LLModelPreview::rebuildUploadData()
}
+void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions)
+{
+ if (!mLODFile[LLModel::LOD_HIGH].empty())
+ {
+ std::string filename = mLODFile[LLModel::LOD_HIGH];
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos)
+ {
+ filename.replace(i, filename.size()-1, ".slm");
+ saveUploadData(filename, save_skinweights, save_joint_positions);
+ }
+ }
+}
+
+void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions)
+{
+ if (!gSavedSettings.getBOOL("MeshImportUseSLM"))
+ {
+ return;
+ }
+
+ std::set<LLPointer<LLModel> > meshes;
+ std::map<LLModel*, std::string> mesh_binary;
+
+ LLModel::hull empty_hull;
+
+ LLSD data;
+
+ S32 mesh_id = 0;
+
+ //build list of unique models and initialize local id
+ for (U32 i = 0; i < mUploadData.size(); ++i)
+ {
+ LLModelInstance& instance = mUploadData[i];
+
+ if (meshes.find(instance.mModel) == meshes.end())
+ {
+ instance.mModel->mLocalID = mesh_id++;
+ meshes.insert(instance.mModel);
+
+ std::stringstream str;
+
+ LLModel::Decomposition& decomp =
+ instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?
+ instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :
+ instance.mModel->mPhysics;
+
+ LLModel::writeModel(str,
+ instance.mLOD[LLModel::LOD_PHYSICS],
+ instance.mLOD[LLModel::LOD_HIGH],
+ instance.mLOD[LLModel::LOD_MEDIUM],
+ instance.mLOD[LLModel::LOD_LOW],
+ instance.mLOD[LLModel::LOD_IMPOSTOR],
+ decomp,
+ save_skinweights, save_joint_positions);
+
+
+ data["mesh"][instance.mModel->mLocalID] = str.str();
+ }
+
+ data["instance"][i] = instance.asLLSD();
+ }
+
+ llofstream out(filename, std::ios_base::out | std::ios_base::binary);
+ LLSDSerialize::toBinary(data, out);
+ out.flush();
+ out.close();
+}
void LLModelPreview::clearModel(S32 lod)
{
@@ -2617,7 +2866,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod)
setPreviewLOD(lod);
- if ( getLoadState() == LLModelLoader::ERROR_PARSING )
+ if ( getLoadState() >= LLModelLoader::ERROR_PARSING )
{
mFMP->childDisable("ok_btn");
}
@@ -2699,44 +2948,129 @@ void LLModelPreview::loadModelCallback(S32 lod)
LLMutexLock lock(this);
if (!mModelLoader)
{
+ mLoading = false ;
return;
}
+ if(getLoadState() >= LLModelLoader::ERROR_PARSING)
+ {
+ mLoading = false ;
+ return ;
+ }
mModelLoader->loadTextures() ;
- mModel[lod] = mModelLoader->mModelList;
- mScene[lod] = mModelLoader->mScene;
- mVertexBuffer[lod].clear();
- if (lod == LLModel::LOD_PHYSICS)
- {
- mPhysicsMesh.clear();
- }
+ if (lod == -1)
+ { //populate all LoDs from model loader scene
+ mBaseModel.clear();
+ mBaseScene.clear();
- setPreviewLOD(lod);
+ bool skin_weights = false;
+ bool joint_positions = false;
+ for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
+ { //for each LoD
- if (lod == LLModel::LOD_HIGH)
- { //save a copy of the highest LOD for automatic LOD manipulation
- if (mBaseModel.empty())
- { //first time we've loaded a model, auto-gen LoD
- mGenLOD = true;
+ //clear scene and model info
+ mScene[lod].clear();
+ mModel[lod].clear();
+ mVertexBuffer[lod].clear();
+
+ if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull())
+ { //if this LoD exists in the loaded scene
+
+ //copy scene to current LoD
+ mScene[lod] = mModelLoader->mScene;
+
+ //touch up copied scene to look like current LoD
+ for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter)
+ {
+ LLModelLoader::model_instance_list& list = iter->second;
+
+ for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter)
+ {
+ //override displayed model with current LoD
+ list_iter->mModel = list_iter->mLOD[lod];
+
+ //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)
+ S32 idx = list_iter->mModel->mLocalID;
+
+ if (mModel[lod].size() <= idx)
+ { //stretch model list to fit model at given index
+ mModel[lod].resize(idx+1);
+ }
+
+ mModel[lod][idx] = list_iter->mModel;
+ if (!list_iter->mModel->mSkinWeights.empty())
+ {
+ skin_weights = true;
+
+ if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty())
+ {
+ joint_positions = true;
+ }
+ }
+ }
+ }
+ }
}
- mBaseModel = mModel[lod];
- clearGLODGroup();
+ if (mFMP)
+ {
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP;
- mBaseScene = mScene[lod];
- mVertexBuffer[5].clear();
- }
+ if (skin_weights)
+ { //enable uploading/previewing of skin weights if present in .slm file
+ fmp->enableViewOption("show_skin_weight");
+ mViewOption["show_skin_weight"] = true;
+ fmp->childSetValue("upload_skin", true);
+ }
- clearIncompatible(lod);
+ if (joint_positions)
+ {
+ fmp->enableViewOption("show_joint_positions");
+ mViewOption["show_joint_positions"] = true;
+ fmp->childSetValue("upload_joints", true);
+ }
+ }
- mDirty = true;
+ //copy high lod to base scene for LoD generation
+ mBaseScene = mScene[LLModel::LOD_HIGH];
+ mBaseModel = mModel[LLModel::LOD_HIGH];
- if (lod == LLModel::LOD_HIGH)
- {
+ mDirty = true;
resetPreviewTarget();
}
+ else
+ { //only replace given LoD
+ mModel[lod] = mModelLoader->mModelList;
+ mScene[lod] = mModelLoader->mScene;
+ mVertexBuffer[lod].clear();
+
+ setPreviewLOD(lod);
+
+ if (lod == LLModel::LOD_HIGH)
+ { //save a copy of the highest LOD for automatic LOD manipulation
+ if (mBaseModel.empty())
+ { //first time we've loaded a model, auto-gen LoD
+ mGenLOD = true;
+ }
+
+ mBaseModel = mModel[lod];
+ clearGLODGroup();
+
+ mBaseScene = mScene[lod];
+ mVertexBuffer[5].clear();
+ }
+
+ clearIncompatible(lod);
+
+ mDirty = true;
+
+ if (lod == LLModel::LOD_HIGH)
+ {
+ resetPreviewTarget();
+ }
+ }
mLoading = false;
refresh();
@@ -2746,8 +3080,12 @@ void LLModelPreview::loadModelCallback(S32 lod)
void LLModelPreview::resetPreviewTarget()
{
- mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f;
- mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f;
+ if ( mModelLoader )
+ {
+ mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f;
+ mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f;
+ }
+
setPreviewTarget(mPreviewScale.magVec()*2.f);
}
@@ -2832,11 +3170,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
return;
}
- if (which_lod == LLModel::LOD_PHYSICS)
- { //clear physics mesh map
- mPhysicsMesh.clear();
- }
-
LLVertexBuffer::unbind();
stop_gloderror();
@@ -3165,11 +3498,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
//of an open problem).
target_model->mPosition = base->mPosition;
target_model->mSkinWeights = base->mSkinWeights;
- target_model->mJointMap = base->mJointMap;
- target_model->mJointList = base->mJointList;
- target_model->mInvBindMatrix = base->mInvBindMatrix;
- target_model->mBindShapeMatrix = base->mBindShapeMatrix;
- target_model->mAlternateBindMatrix = base->mAlternateBindMatrix;
+ target_model->mSkinInfo = base->mSkinInfo;
//copy material list
target_model->mMaterialList = base->mMaterialList;
@@ -3362,7 +3691,7 @@ void LLModelPreview::updateStatusMessages()
}
}
- bool errorStateFromLoader = getLoadState() == LLModelLoader::ERROR_PARSING ? true : false;
+ bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false;
bool skinAndRigOk = true;
bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean();
@@ -3389,7 +3718,7 @@ void LLModelPreview::updateStatusMessages()
LLModel* model = mModel[LLModel::LOD_PHYSICS][i];
S32 cur_submeshes = model->getNumVolumeFaces();
- LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp;
+ LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;
if (!decomp.empty())
{
@@ -3968,9 +4297,9 @@ BOOL LLModelPreview::render()
glColor4fv(instance.mMaterial[i].mDiffuseColor.mV);
if (i < instance.mMaterial.size() && instance.mMaterial[i].mDiffuseMap.notNull())
{
- gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
if (instance.mMaterial[i].mDiffuseMap->getDiscardLevel() > -1)
{
+ gGL.getTexUnit(0)->bind(instance.mMaterial[i].mDiffuseMap, true);
mTextureSet.insert(instance.mMaterial[i].mDiffuseMap.get());
}
}
@@ -4026,12 +4355,17 @@ BOOL LLModelPreview::render()
{
LLMutexLock(decomp->mMutex);
- std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > >::iterator iter =
- mPhysicsMesh.find(model);
- if (iter != mPhysicsMesh.end())
+ LLModel::Decomposition& physics = model->mPhysics;
+
+ if (physics.mMesh.empty())
+ { //build vertex buffer for physics mesh
+ gMeshRepo.buildPhysicsMesh(physics);
+ }
+
+ if (!physics.mMesh.empty())
{ //render hull instead of mesh
render_mesh = false;
- for (U32 i = 0; i < iter->second.size(); ++i)
+ for (U32 i = 0; i < physics.mMesh.size(); ++i)
{
if (explode > 0.f)
{
@@ -4050,14 +4384,8 @@ BOOL LLModelPreview::render()
hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255));
}
- LLVertexBuffer* buff = iter->second[i];
- if (buff)
- {
- buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
-
glColor4ubv(hull_colors[i].mV);
- buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
- }
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
if (explode > 0.f)
{
@@ -4141,12 +4469,12 @@ BOOL LLModelPreview::render()
//build matrix palette
LLMatrix4 mat[64];
- for (U32 j = 0; j < model->mJointList.size(); ++j)
+ for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j)
{
- LLJoint* joint = avatar->getJoint(model->mJointList[j]);
+ LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]);
if (joint)
{
- mat[j] = model->mInvBindMatrix[j];
+ mat[j] = model->mSkinInfo.mInvBindMatrix[j];
mat[j] *= joint->getWorldMatrix();
}
}
@@ -4187,7 +4515,7 @@ BOOL LLModelPreview::render()
//VECTORIZE THIS
LLVector3 v(face.mPositions[j].getF32ptr());
- v = v * model->mBindShapeMatrix;
+ v = v * model->mSkinInfo.mBindShapeMatrix;
v = v * final_mat;
position[j] = v;
@@ -4266,9 +4594,12 @@ void LLModelPreview::setPreviewLOD(S32 lod)
mFMP->childSetTextArg("lod_table_footer", "[DETAIL]", mFMP->getString(lod_name[mPreviewLOD]));
mFMP->childSetText("lod_file", mLODFile[mPreviewLOD]);
- // the wizard has two lod drop downs
+ // the wizard has three lod drop downs
LLComboBox* combo_box2 = mFMP->getChild<LLComboBox>("preview_lod_combo2");
combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
+
+ LLComboBox* combo_box3 = mFMP->getChild<LLComboBox>("preview_lod_combo3");
+ combo_box3->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor");
LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor");
@@ -4304,6 +4635,17 @@ void LLFloaterModelPreview::onBrowseLOD(void* data)
}
//static
+void LLFloaterModelPreview::onReset(void* user_data)
+{
+ assert_main_thread();
+
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
+ LLModelPreview* mp = fmp->mModelPreview;
+ std::string filename = mp->mLODFile[3];
+ mp->loadModel(filename,3);
+}
+
+//static
void LLFloaterModelPreview::onUpload(void* user_data)
{
assert_main_thread();
@@ -4317,8 +4659,13 @@ void LLFloaterModelPreview::onUpload(void* user_data)
mp->mModelPreview->rebuildUploadData();
+ bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean();
+ bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean();
+
+ mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions);
+
gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale,
- mp->childGetValue("upload_textures").asBoolean(), mp->childGetValue("upload_skin"), mp->childGetValue("upload_joints"));
+ mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions);
mp->closeFloater(false);
}
@@ -4429,7 +4776,6 @@ void LLFloaterModelPreview::DecompRequest::completed()
{
if (sInstance->mModelPreview)
{
- sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;
sInstance->mModelPreview->mDirty = true;
LLFloaterModelPreview::sInstance->mModelPreview->refresh();
}