diff options
Diffstat (limited to 'indra/newview/llfloatermodelpreview.cpp')
-rwxr-xr-x | indra/newview/llfloatermodelpreview.cpp | 295 |
1 files changed, 272 insertions, 23 deletions
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ce977b33bb..6145c6c16d 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" @@ -1087,8 +1089,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->mBaseModel.empty(); mPreview->setLoadState(STARTING); } + else + { + mTrySLM = false; + } } void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) @@ -1166,6 +1175,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); @@ -1743,6 +1784,91 @@ 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->createVolumeFacesFromStream(str)) + { + loaded_model->mLocalID = i; + model[lod].push_back(loaded_model); + } + 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); + } + + return true; +} + void LLModelLoader::loadModelCallback() { if (mPreview) @@ -2561,6 +2687,70 @@ 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) +{ + 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::convex_hull_decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? + instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : + instance.mModel->mConvexHullDecomp; + + 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, + empty_hull, 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) { @@ -2703,39 +2893,93 @@ void LLModelPreview::loadModelCallback(S32 lod) } 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); + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { //for each LoD + //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 - 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; + //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; + } + } + } } - mBaseModel = mModel[lod]; - clearGLODGroup(); + //copy high lod to base scene for LoD generation + mBaseScene = mScene[LLModel::LOD_HIGH]; + mBaseModel = mModel[LLModel::LOD_HIGH]; - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); + mDirty = true; + resetPreviewTarget(); } + else + { //only replace given LoD + mModel[lod] = mModelLoader->mModelList; + mScene[lod] = mModelLoader->mScene; + mVertexBuffer[lod].clear(); - clearIncompatible(lod); + if (lod == LLModel::LOD_PHYSICS) + { + mPhysicsMesh.clear(); + } - mDirty = true; + setPreviewLOD(lod); - if (lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); + + 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; @@ -4317,8 +4561,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); } |