diff --git a/indra/newview/skins/default/xui/en/floater_vj_local_mesh.xml b/indra/newview/skins/default/xui/en/floater_vj_local_mesh.xml
index 7bc18dfed2..7cfdeaef85 100644
--- a/indra/newview/skins/default/xui/en/floater_vj_local_mesh.xml
+++ b/indra/newview/skins/default/xui/en/floater_vj_local_mesh.xml
@@ -1,168 +1,317 @@
-
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
+ left="3"
+ ignore_tab="false"
+ right="-2"
+ top_pad="0"/>
+
+
+
+
+
+
+
+ LOD Suffixes:
+
+
+ Current
+ SL Standard
+ Games Engine Standard
+ LOD Names
+
+
+ Lowest:
+
+
+
+ Low:
+
+
+
+ Medium:
+
+
+
+ High:
+
+
+
+ Physics:
+
+
+
-
-
+
-
+ width="315"
+ visible="true">
/>
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/indra/newview/vjfloaterlocalmesh.cpp b/indra/newview/vjfloaterlocalmesh.cpp
index 89e95a4a78..3f7c636d06 100644
--- a/indra/newview/vjfloaterlocalmesh.cpp
+++ b/indra/newview/vjfloaterlocalmesh.cpp
@@ -29,6 +29,7 @@
#include "llfilepicker.h"
#include "llinventoryicon.h"
+#include "llviewercontrol.h"
#include "llviewermenufile.h"
#include "fsscrolllistctrl.h"
#include "llcheckboxctrl.h"
@@ -37,6 +38,7 @@
#include "llselectmgr.h"
#include "lltoolmgr.h"
#include "lltoolcomp.h"
+#include "llmodelpreview.h"
#include "llviewerobjectlist.h"
@@ -125,8 +127,6 @@ BOOL LLFloaterLocalMesh::postBuild()
childSetAction("btn_clear", LLFloaterLocalMesh::onBtnClear, this);
childSetAction("btn_rez", LLFloaterLocalMesh::onBtnRez, this);
-
-
mTabContainer = findChild("local_mesh_tabs");
if(mTabContainer)
{
@@ -136,6 +136,7 @@ BOOL LLFloaterLocalMesh::postBuild()
// mTabContainer->setCommitCallback(boost::bind(&LLFloaterLocalMesh::onTabChange, this));
}
+ getChild("lod_suffix_combo")->setCommitCallback(boost::bind(&LLFloaterLocalMesh::onSuffixStandardSelected, this, (LLUICtrl*)this));
reloadLowerUI();
return TRUE;
@@ -173,14 +174,10 @@ void LLFloaterLocalMesh::onBtnAdd(void* userdata)
void LLFloaterLocalMesh::onBtnAddCallback(std::string filename)
{
- bool try_lods = false;
- auto checkbox_use_lods = getChild("chkbox_use_lods");
- if (checkbox_use_lods)
- {
- try_lods = checkbox_use_lods->get();
- }
+ static const bool try_lods {true};
LLLocalMeshSystem::getInstance()->addFile(filename, try_lods);
+ showLog();
}
@@ -261,14 +258,6 @@ void LLFloaterLocalMesh::onBtnApply(void* userdata)
return;
}
- // checkbox pointer
- bool use_scale = false;
- auto checkbox_use_scale = self->getChild("chkbox_use_scale");
- if (checkbox_use_scale)
- {
- use_scale = checkbox_use_scale->get();
- }
-
// make sure the selection is still valid, and if so - get id.
LLUUID selected_object_id = self->getCurrentSelectionIfValid();
if (selected_object_id.isNull())
@@ -281,7 +270,75 @@ void LLFloaterLocalMesh::onBtnApply(void* userdata)
int object_idx = objectlist_combo_box->getFirstSelectedIndex();
// finally tell local mesh system to apply
- LLLocalMeshSystem::getInstance()->applyVObject(selected_object_id, file_id, object_idx, use_scale);
+ LLLocalMeshSystem::getInstance()->applyVObject(selected_object_id, file_id, object_idx, true);
+}
+
+//static
+void LLFloaterLocalMesh::onSuffixStandardSelected(LLUICtrl* ctrl, void* userdata)
+{
+ S32 which{0};
+// SL standard LODs are the reverse of every other game engine (LOD0 least detail)
+// SL has no suffix for the HIGH LOD
+ static const std::array sl_suffixes = {
+ "LOD0",
+ "LOD1",
+ "LOD2",
+ "",
+ "PHYS"
+ };
+// Game engines (UE, Unity, CryEngine, Godot, etc.) all use LOD0 as highest.
+// They typically also label the high with a suffix too
+ static const std::array std_suffixes = {
+ "LOD3",
+ "LOD2",
+ "LOD1",
+ "LOD0",
+ "PHYS"
+ };
+// Human friendly. When making things manually people naturally use names.
+ static const std::array desc_suffixes = {
+ "LOWEST",
+ "LOW",
+ "MED",
+ "HIGH",
+ "PHYS"
+ };
+ auto * self = (LLFloaterLocalMesh *)ctrl;
+
+ if (LLCtrlSelectionInterface* iface = self->childGetSelectionInterface("lod_suffix_combo"))
+ {
+ which = iface->getFirstSelectedIndex();
+ }
+ else
+ {
+ LL_WARNS() << "no UI element found! nothing changed" << LL_ENDL;
+ return;
+ }
+ gSavedSettings.setS32("FSMeshLodSuffixScheme",which);
+ switch (which)
+ {
+ case 1: // SL
+ for (int i = 0; i < LLModel::NUM_LODS; i++)
+ {
+ gSavedSettings.setString(LLModelPreview::sSuffixVarNames[i], sl_suffixes[i]);
+ }
+ break;
+ case 2: // standard
+ for (int i = 0; i < LLModel::NUM_LODS; i++)
+ {
+ gSavedSettings.setString(LLModelPreview::sSuffixVarNames[i], std_suffixes[i]);
+ }
+ break;
+ case 3: // descriptive english
+ for (int i = 0; i < LLModel::NUM_LODS; i++)
+ {
+ gSavedSettings.setString(LLModelPreview::sSuffixVarNames[i], desc_suffixes[i]);
+ }
+ break;
+ default:
+ LL_WARNS() << "no standard selected, nothing changed" << LL_ENDL;
+ break;
+ };
}
void LLFloaterLocalMesh::onBtnClear(void* userdata)
@@ -303,11 +360,6 @@ void LLFloaterLocalMesh::onBtnClear(void* userdata)
bool LLFloaterLocalMesh::processPrimCreated(LLViewerObject* object)
{
- // Make sure we are expecting this.
- // if (!mRezPending)
- // {
- // return false;
- // }
if(!object)
{
return false;
@@ -357,25 +409,21 @@ bool LLFloaterLocalMesh::processPrimCreated(LLViewerObject* object)
{
local_id = scroll_ctrl_selected_column->getValue().asUUID();
// fill it up with local goodness
- bool use_scale = false;
- auto checkbox_use_scale = this->getChild("chkbox_use_scale");
- if (checkbox_use_scale)
- {
- use_scale = checkbox_use_scale->get();
- }
+ static const bool use_scale {true};
// // make sure the selection is still valid, and if so - get id.
// get selected local file id, object idx and use_scale boolean
int object_idx = objectlist_combo_box->getFirstSelectedIndex();
LLLocalMeshSystem::getInstance()->applyVObject(object->getID(), local_id, object_idx, use_scale);
- auto* volp = object->getVolume();
+ volp = object->getVolume();
if(!volp)
{
return true;
}
volume_params = volp->getParams();
object->updateVolume(volume_params);
+ object->markForUpdate(true);
}
return true;
}
@@ -481,9 +529,6 @@ void LLFloaterLocalMesh::reloadFileList(bool keep_selection)
LLAssetType::AT_OBJECT,
LLInventoryType::IT_OBJECT);
LLSD element;
- element["columns"][0]["column"] = "drag to rez";
- element["columns"][0]["type"] = "icon";
- element["columns"][0]["value"] = icon_name;
element["columns"][0]["column"] = "unit_status";
element["columns"][0]["type"] = "text";
@@ -514,11 +559,11 @@ void LLFloaterLocalMesh::reloadFileList(bool keep_selection)
mScrollCtrl->selectNthItem(selected_num);
reloadLowerUI();
}
- else if (mScrollCtrl->getItemCount() == 1)
+ else if (mScrollCtrl->getItemCount() > 0)
{
- // if we've just got the one item, select it.
- // this prevents the need to explicitly select a list item when first adding a file.
- mScrollCtrl->selectNthItem(0);
+ // select the last item in the list
+ mScrollCtrl->selectNthItem( mScrollCtrl->getItemCount()-1 );
+ reloadLowerUI();
}
}
diff --git a/indra/newview/vjfloaterlocalmesh.h b/indra/newview/vjfloaterlocalmesh.h
index 7dd423a34d..e5963b12cf 100644
--- a/indra/newview/vjfloaterlocalmesh.h
+++ b/indra/newview/vjfloaterlocalmesh.h
@@ -59,6 +59,7 @@ class LLFloaterLocalMesh : public LLFloater
static void onBtnApply(void* userdata);
static void onBtnClear(void* userdata);
static void onBtnRez(void* userdata);
+ static void onSuffixStandardSelected(LLUICtrl* ctrl, void *userdata);
bool processPrimCreated(LLViewerObject* object);
diff --git a/indra/newview/vjlocalmesh.cpp b/indra/newview/vjlocalmesh.cpp
index 6f0ceedbee..9f290eab61 100644
--- a/indra/newview/vjlocalmesh.cpp
+++ b/indra/newview/vjlocalmesh.cpp
@@ -33,6 +33,7 @@
#include "llvolumemgr.h"
#include "pipeline.h"
#include "llviewercontrol.h"
+#include "llmodelpreview.h"
// STL headers
#include
@@ -359,8 +360,10 @@ LLLocalMeshFile::LLLocalMeshFile(const std::string& filename, bool try_lods)
mLocalMeshFileNeedsUIUpdate = false;
mLoadedObjectList.clear();
mSavedObjectSculptIDs.clear();
-
- pushLog("LLLocalMeshFile", "Initializing with filename: " + filename);
+
+ mShortName = std::string(boost::filesystem::path(filename).stem().string());
+ auto base_lod_filename {stripSuffix(mShortName)};
+ pushLog("LLLocalMeshFile", "Initializing with base filename: " + base_lod_filename);
// check if main filename exists, just in case
if (!boost::filesystem::exists(filename))
@@ -371,8 +374,8 @@ LLLocalMeshFile::LLLocalMeshFile(const std::string& filename, bool try_lods)
return;
}
- mFilenames[3] = filename;
- mShortName = boost::filesystem::path(filename).filename().generic_string();
+ // for the high lod we just store the filename fromthe file picker
+ mFilenames[LOCAL_LOD_HIGH] = filename;
// check if we have a valid extension, can't switch with string can we?
if (std::string exten_str = boost::filesystem::extension(filename); exten_str == ".dae")
@@ -442,38 +445,32 @@ void LLLocalMeshFile::reloadLocalMeshObjects(bool initial_load)
// check for lod filenames
if (mTryLODFiles)
{
- size_t dot_position = mFilenames[LOCAL_LOD_HIGH].find_last_of(".");
- if (dot_position == mFilenames[LOCAL_LOD_HIGH].npos)
- {
- // should theoretically never happen, we did check extension before,
- // but "should never happen" doesn't mean we shouldn't check.
- pushLog("LLLocalMeshFile", "Filename extension error, loading stopped.", true);
- mLocalMeshFileStatus = LLLocalMeshFileStatus::STATUS_ERROR;
- return;
- }
-
pushLog("LLLocalMeshFile", "Seeking LOD files...");
// up to LOD2, LOD3 being the highest is always done by this point.
- for (size_t lodfile_iter = LOCAL_LOD_LOWEST; lodfile_iter < LOCAL_LOD_HIGH; ++lodfile_iter)
+ for (S32 lodfile_iter = LOCAL_LOD_LOWEST; lodfile_iter < LOCAL_LOD_HIGH; ++lodfile_iter)
{
- std::string current_lod_filename = mFilenames[LOCAL_LOD_HIGH];
- std::string lod_string = "_LOD" + std::to_string(lodfile_iter);
-
- current_lod_filename.insert(dot_position, lod_string);
- if (boost::filesystem::exists(current_lod_filename))
+ // lod filenames may be empty because this is first time through or because the lod didn't exist before.
+ if( mFilenames[lodfile_iter].empty() )
{
- pushLog("LLLocalMeshFile", "LOD filename " + current_lod_filename + " found, adding.");
- mFilenames[lodfile_iter] = current_lod_filename;
- }
+ auto filepath { boost::filesystem::path(mFilenames[LOCAL_LOD_HIGH]).parent_path() };
+ auto lod_suffix { getLodSuffix(lodfile_iter) };
+ auto extension { boost::filesystem::path(mFilenames[LOCAL_LOD_HIGH]).extension() };
- else
- {
- pushLog("LLLocalMeshFile", "LOD filename " + current_lod_filename + " not found, skipping.");
- mFilenames[lodfile_iter].clear();
+ boost::filesystem::path current_lod_filename = filepath / (mShortName + lod_suffix + extension.string());
+ if ( boost::filesystem::exists( current_lod_filename ) )
+ {
+ pushLog("LLLocalMeshFile", "LOD filename " + current_lod_filename.string() + " found, adding.");
+ mFilenames[lodfile_iter] = current_lod_filename.string();
+ }
+
+ else
+ {
+ pushLog("LLLocalMeshFile", "LOD filename " + current_lod_filename.string() + " not found, skipping.");
+ mFilenames[lodfile_iter].clear();
+ }
}
}
}
-
else
{
pushLog("LLLocalMeshFile", "Skipping LOD 2-0 files, as specified.");
@@ -759,7 +756,6 @@ void LLLocalMeshFile::applyToVObject(LLUUID viewer_object_id, int object_index,
if ((!target_object->isAttachment()) && use_scale)
{
auto scale = mLoadedObjectList[object_index]->getObjectSize();
- // scale *= 0.01; /* NOTE: magic number */
target_object->setScale(LLVector3(scale), false);
}
@@ -803,7 +799,7 @@ void LLLocalMeshSystem::addFile(const std::string& filename, bool try_lods)
{
auto loaded_file = std::make_unique(filename, try_lods);
mLoadedFileList.push_back(std::move(loaded_file));
- triggerFloaterRefresh();
+ triggerFloaterRefresh(false);
triggerCheckFileAsyncStatus();
}
@@ -970,11 +966,11 @@ void LLLocalMeshSystem::registerFloaterPointer(LLFloaterLocalMesh* floater_ptr)
mFloaterPtr = floater_ptr;
}
-void LLLocalMeshSystem::triggerFloaterRefresh()
+void LLLocalMeshSystem::triggerFloaterRefresh(bool keep_selection)
{
if (mFloaterPtr)
{
- mFloaterPtr->reloadFileList(true);
+ mFloaterPtr->reloadFileList(keep_selection);
}
}
diff --git a/indra/newview/vjlocalmesh.h b/indra/newview/vjlocalmesh.h
index 32261c5cb4..e50ac6ba43 100644
--- a/indra/newview/vjlocalmesh.h
+++ b/indra/newview/vjlocalmesh.h
@@ -244,7 +244,7 @@ class LLLocalMeshSystem : public LLSingleton
// floater two-way communication
void registerFloaterPointer(LLFloaterLocalMesh* floater_ptr);
- void triggerFloaterRefresh();
+ void triggerFloaterRefresh( bool keep_selection=true );
std::vector getFileInfoVector() const;
std::vector getFileLog(LLUUID local_file_id) const;
diff --git a/indra/newview/vjlocalmeshimportdae.cpp b/indra/newview/vjlocalmeshimportdae.cpp
index 4541b73699..2a500ac362 100644
--- a/indra/newview/vjlocalmeshimportdae.cpp
+++ b/indra/newview/vjlocalmeshimportdae.cpp
@@ -99,16 +99,24 @@ LLLocalMeshImportDAE::loadFile_return LLLocalMeshImportDAE::loadFile(LLLocalMesh
LLMatrix4 scene_transform_base;
- domAsset::domUnit* unit = daeSafeCast(collada_document_root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
- scene_transform_base.setIdentity();
- if (unit)
- {
- F32 meter = unit->getMeter();
- scene_transform_base.mMatrix[0][0] = meter;
- scene_transform_base.mMatrix[1][1] = meter;
- scene_transform_base.mMatrix[2][2] = meter;
- }
+ static auto always_use_meter_scale = LLUICachedControl("FSLocalMeshScaleAlwaysMeters", false);
+ if(!always_use_meter_scale)
+ {
+ domAsset::domUnit* unit = daeSafeCast(collada_document_root->getDescendant(daeElement::matchType(domAsset::domUnit::ID())));
+ scene_transform_base.setIdentity();
+ if (unit)
+ {
+ F32 meter = unit->getMeter();
+ scene_transform_base.mMatrix[0][0] = meter;
+ scene_transform_base.mMatrix[1][1] = meter;
+ scene_transform_base.mMatrix[2][2] = meter;
+ }
+ }
+ else
+ {
+ scene_transform_base.setIdentity();
+ }
//get up axis rotation
LLMatrix4 rotation;
@@ -468,7 +476,8 @@ bool LLLocalMeshImportDAE::processSkin(daeDatabase* collada_db, daeElement* coll
auto& skininfo = current_object->getObjectMeshSkinInfo();
// basically copy-pasted from linden magic
- LLMatrix4 normalized_transformation, mesh_scale;
+ LLMatrix4 normalized_transformation;
+ LLMatrix4 mesh_scale;
normalized_transformation.setTranslation(LLVector3(inverse_translation));
mesh_scale.initScale(LLVector3(objct_size));
mesh_scale *= normalized_transformation;