summaryrefslogtreecommitdiff
path: root/indra/newview/llfloatermodelpreview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llfloatermodelpreview.cpp')
-rw-r--r--indra/newview/llfloatermodelpreview.cpp1041
1 files changed, 831 insertions, 210 deletions
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index e12ad262f8..10db8ac3bc 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -76,6 +76,7 @@
#include "llsdserialize.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
+#include "lltabcontainer.h"
#include "lltoggleablemenu.h"
#include "lltrans.h"
#include "llvfile.h"
@@ -83,6 +84,7 @@
#include "llcallbacklist.h"
#include "llviewerobjectlist.h"
#include "llanimationstates.h"
+#include "llviewertexteditor.h"
#include "llviewernetwork.h"
#include "llviewershadermgr.h"
@@ -108,6 +110,8 @@ const double RETAIN_COEFFICIENT = 100;
// So this const is used as a size of Smooth combobox list.
const S32 SMOOTH_VALUES_NUMBER = 10;
+const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f;
+
void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
@@ -261,7 +265,9 @@ void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LL
LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) :
LLFloaterModelUploadBase(key),
mUploadBtn(NULL),
-mCalculateBtn(NULL)
+mCalculateBtn(NULL),
+mUploadLogText(NULL),
+mTabContainer(NULL)
{
sInstance = this;
mLastMouseX = 0;
@@ -304,10 +310,10 @@ BOOL LLFloaterModelPreview::postBuild()
getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLODParamCommit, this, lod, true));
}
- childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
- childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
- childSetCommitCallback("lock_scale_if_joint_position", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
- childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this), NULL);
+ childSetCommitCallback("upload_skin", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL);
+ childSetCommitCallback("upload_joints", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL);
+ childSetCommitCallback("lock_scale_if_joint_position", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL);
+ childSetCommitCallback("upload_textures", boost::bind(&LLFloaterModelPreview::onUploadOptionChecked, this, _1), NULL);
childSetTextArg("status", "[STATUS]", getString("status_idle"));
@@ -330,13 +336,17 @@ BOOL LLFloaterModelPreview::postBuild()
getChild<LLCheckBoxCtrl>("show_edges")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
getChild<LLCheckBoxCtrl>("show_physics")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
getChild<LLCheckBoxCtrl>("show_textures")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
- getChild<LLCheckBoxCtrl>("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
+ getChild<LLCheckBoxCtrl>("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onShowSkinWeightChecked, this, _1));
+ getChild<LLCheckBoxCtrl>("show_joint_overrides")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
getChild<LLCheckBoxCtrl>("show_joint_positions")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1));
childDisable("upload_skin");
childDisable("upload_joints");
childDisable("lock_scale_if_joint_position");
+ childSetVisible("skin_too_many_joints", false);
+ childSetVisible("skin_unknown_joint", false);
+
initDecompControls();
LLView* preview_panel = getChild<LLView>("preview_panel");
@@ -392,6 +402,19 @@ BOOL LLFloaterModelPreview::postBuild()
mUploadBtn = getChild<LLButton>("ok_btn");
mCalculateBtn = getChild<LLButton>("calculate_btn");
+ mUploadLogText = getChild<LLViewerTextEditor>("log_text");
+ mTabContainer = getChild<LLTabContainer>("import_tab");
+
+ // Disable Overrides tab untill it has something to show and set callbacks
+ LLPanel *panel = mTabContainer->getPanelByName("overrides_panel");
+ S32 index = mTabContainer->getIndexForPanel(panel);
+ mTabContainer->enableTabButton(index, false);
+ panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this));
+
+ // Disable Logs tab untill it has something to show
+ panel = mTabContainer->getPanelByName("logs_panel");
+ index = mTabContainer->getIndexForPanel(panel);
+ mTabContainer->enableTabButton(index, false);
if (LLConvexDecomposition::getInstance() != NULL)
{
@@ -430,18 +453,58 @@ void LLFloaterModelPreview::initModelPreview()
delete mModelPreview;
}
- mModelPreview = new LLModelPreview(512, 512, this );
+ S32 tex_width = 512;
+ S32 tex_height = 512;
+
+ S32 max_width = llmin(gSavedSettings.getS32("PreviewRenderSize"), (S32)gPipeline.mScreenWidth);
+ S32 max_height = llmin(gSavedSettings.getS32("PreviewRenderSize"), (S32)gPipeline.mScreenHeight);
+
+ while ((tex_width << 1) <= max_width)
+ {
+ tex_width <<= 1;
+ }
+ while ((tex_height << 1) <= max_height)
+ {
+ tex_height <<= 1;
+ }
+
+ mModelPreview = new LLModelPreview(tex_width, tex_height, this);
mModelPreview->setPreviewTarget(16.f);
mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5));
mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::modelUpdated, this, _1));
}
+void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl)
+{
+ if (mModelPreview)
+ {
+ auto name = ctrl->getName();
+ mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name];
+ }
+ toggleCalculateButton(true);
+}
+
+void LLFloaterModelPreview::onShowSkinWeightChecked(LLUICtrl* ctrl)
+{
+ if (mModelPreview)
+ {
+ mModelPreview->mCameraOffset.clearVec();
+ onViewOptionChecked(ctrl);
+ }
+}
+
void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl)
{
if (mModelPreview)
{
- mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()];
-
+ auto name = ctrl->getName();
+ mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name];
+ if (name == "show_physics")
+ {
+ auto enabled = mModelPreview->mViewOption[name];
+ childSetEnabled("physics_explode", enabled);
+ childSetVisible("physics_explode", enabled);
+ }
mModelPreview->refresh();
}
}
@@ -497,6 +560,8 @@ void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name, boo
void LLFloaterModelPreview::onClickCalculateBtn()
{
+ clearLogTab();
+
mModelPreview->rebuildUploadData();
bool upload_skinweights = childGetValue("upload_skin").asBoolean();
@@ -523,6 +588,79 @@ void LLFloaterModelPreview::onClickCalculateBtn()
mUploadBtn->setEnabled(false);
}
+void populate_list_with_map(LLScrollListCtrl *list, const std::map<std::string, LLVector3> &vector_map)
+{
+ if (vector_map.empty())
+ {
+ return;
+ }
+ S32 count = 0;
+ LLScrollListCell::Params cell_params;
+ cell_params.font = LLFontGL::getFontSansSerif();
+ // Start out right justifying numeric displays
+ cell_params.font_halign = LLFontGL::HCENTER;
+
+ std::map<std::string, LLVector3>::const_iterator iter = vector_map.begin();
+ std::map<std::string, LLVector3>::const_iterator end = vector_map.end();
+ while (iter != end)
+ {
+ LLScrollListItem::Params item_params;
+ item_params.value = LLSD::Integer(count);
+
+ cell_params.column = "model_name";
+ cell_params.value = iter->first;
+
+ item_params.columns.add(cell_params);
+
+ cell_params.column = "axis_x";
+ cell_params.value = iter->second.mV[VX];
+ item_params.columns.add(cell_params);
+
+ cell_params.column = "axis_y";
+ cell_params.value = iter->second.mV[VY];
+ item_params.columns.add(cell_params);
+
+ cell_params.column = "axis_z";
+ cell_params.value = iter->second.mV[VZ];
+
+ item_params.columns.add(cell_params);
+
+ list->addRow(item_params);
+ count++;
+ iter++;
+ }
+}
+
+void LLFloaterModelPreview::onJointListSelection()
+{
+ S32 display_lod = mModelPreview->mPreviewLOD;
+ LLPanel *panel = mTabContainer->getPanelByName("overrides_panel");
+ LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list");
+ LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list");
+ LLScrollListCtrl *joints_scale = panel->getChild<LLScrollListCtrl>("scale_overrides_list");
+ LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("pos_overrides_descr");
+
+ joints_pos->deleteAllItems();
+ joints_scale->deleteAllItems();
+
+ LLScrollListItem *selected = joints_list->getFirstSelected();
+ if (selected)
+ {
+ std::string label = selected->getValue().asString();
+ LLJointOverrideData &data = mJointOverrides[display_lod][label];
+ populate_list_with_map(joints_pos, data.mPosOverrides);
+
+ joint_pos_descr->setTextArg("[JOINT]", label);
+ }
+ else
+ {
+ // temporary value (shouldn't happen)
+ std::string label = "mPelvis";
+ joint_pos_descr->setTextArg("[JOINT]", label);
+ }
+
+}
+
void LLFloaterModelPreview::onDescriptionKeystroke(LLUICtrl* ctrl)
{
// Workaround for SL-4186, server doesn't allow name changes after 'calculate' stage
@@ -623,6 +761,7 @@ void LLFloaterModelPreview::onGenerateNormalsCommit(LLUICtrl* ctrl, void* userda
void LLFloaterModelPreview::toggleGenarateNormals()
{
bool enabled = childGetValue("gen_normals").asBoolean();
+ mModelPreview->mViewOption["gen_normals"] = enabled;
childSetEnabled("crease_angle", enabled);
if(enabled) {
mModelPreview->generateNormals();
@@ -666,6 +805,42 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
}
}
+void LLFloaterModelPreview::draw3dPreview()
+{
+ gGL.color3f(1.f, 1.f, 1.f);
+
+ gGL.getTexUnit(0)->bind(mModelPreview);
+
+
+ LLView* preview_panel = getChild<LLView>("preview_panel");
+
+ if (!preview_panel)
+ {
+ LL_WARNS() << "preview_panel not found in floater definition" << LL_ENDL;
+ }
+ LLRect rect = preview_panel->getRect();
+
+ if (rect != mPreviewRect)
+ {
+ mModelPreview->refresh();
+ mPreviewRect = preview_panel->getRect();
+ }
+
+ gGL.begin( LLRender::QUADS );
+ {
+ gGL.texCoord2f(0.f, 1.f);
+ gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop-1);
+ gGL.texCoord2f(0.f, 0.f);
+ gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom);
+ gGL.texCoord2f(1.f, 0.f);
+ gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom);
+ gGL.texCoord2f(1.f, 1.f);
+ gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1);
+ }
+ gGL.end();
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+}
//-----------------------------------------------------------------------------
// draw()
@@ -1112,10 +1287,8 @@ void LLFloaterModelPreview::initDecompControls()
std::string label = llformat("%.1f", value);
combo_box->add(label, value, ADD_BOTTOM, true);
}
- combo_box->setValue(param[i].mDefault.mFloat);
-
}
-
+ combo_box->setValue(param[i].mDefault.mFloat);
combo_box->setCommitCallback(onPhysicsParamCommit, (void*) &param[i]);
}
}
@@ -1187,7 +1360,7 @@ void LLFloaterModelPreview::initDecompControls()
//LL_INFOS() << "-----------------------------" << LL_ENDL;
}
}
-
+ mDefaultDecompParams = mDecompParams;
childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this);
}
@@ -1217,6 +1390,205 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
}
//-----------------------------------------------------------------------------
+// addStringToLog()
+//-----------------------------------------------------------------------------
+//static
+void LLFloaterModelPreview::addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod)
+{
+ if (sInstance && sInstance->hasString(message))
+ {
+ std::string str;
+ switch (lod)
+ {
+ case LLModel::LOD_IMPOSTOR: str = "LOD0 "; break;
+ case LLModel::LOD_LOW: str = "LOD1 "; break;
+ case LLModel::LOD_MEDIUM: str = "LOD2 "; break;
+ case LLModel::LOD_PHYSICS: str = "PHYS "; break;
+ case LLModel::LOD_HIGH: str = "LOD3 "; break;
+ default: break;
+ }
+
+ LLStringUtil::format_map_t args_msg;
+ LLSD::map_const_iterator iter = args.beginMap();
+ LLSD::map_const_iterator end = args.endMap();
+ for (; iter != end; ++iter)
+ {
+ args_msg[iter->first] = iter->second.asString();
+ }
+ str += sInstance->getString(message, args_msg);
+ sInstance->addStringToLogTab(str, flash);
+ }
+}
+
+// static
+void LLFloaterModelPreview::addStringToLog(const std::string& str, bool flash)
+{
+ if (sInstance)
+ {
+ sInstance->addStringToLogTab(str, flash);
+ }
+}
+
+// static
+void LLFloaterModelPreview::addStringToLog(const std::ostringstream& strm, bool flash)
+{
+ if (sInstance)
+ {
+ sInstance->addStringToLogTab(strm.str(), flash);
+ }
+}
+
+void LLFloaterModelPreview::clearOverridesTab()
+{
+ LLPanel *panel = mTabContainer->getPanelByName("overrides_panel");
+ LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list");
+ joints_list->deleteAllItems();
+
+ for (U32 i = 0; i < LLModel::NUM_LODS; ++i)
+ {
+ mJointOverrides[i].clear();
+ }
+}
+
+void LLFloaterModelPreview::resetOverridesTab()
+{
+ clearOverridesTab();
+
+ for (U32 i = 0; i < LLModel::NUM_LODS; ++i)
+ {
+ mJointOverrides[i].clear();
+ }
+}
+
+void LLFloaterModelPreview::showOverridesTab()
+{
+ S32 display_lod = mModelPreview->mPreviewLOD;
+ if (mModelPreview->mModel[display_lod].empty())
+ {
+ return;
+ }
+
+ // Joints will be listed as long as they are listed in mAlternateBindMatrix
+ // even if they are for some reason identical to defaults.
+ // Todo: Are overrides always identical for all lods? They normally are, but there might be situations where they aren't.
+ if (mJointOverrides[display_lod].empty())
+ {
+ // populate map
+ for (LLModelLoader::scene::iterator iter = mModelPreview->mScene[display_lod].begin(); iter != mModelPreview->mScene[display_lod].end(); ++iter)
+ {
+ for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter)
+ {
+ LLModelInstance& instance = *model_iter;
+ LLModel* model = instance.mModel;
+ const LLMeshSkinInfo *skin = &model->mSkinInfo;
+ if (skin->mAlternateBindMatrix.size() > 0)
+ {
+ U32 count = LLSkinningUtil::getMeshJointCount(skin);
+ for (U32 j = 0; j < count; ++j)
+ {
+ const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation();
+ LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]];
+ if (data.mPosOverrides.size() > 0
+ && (data.mPosOverrides.begin()->second - jointPos).lengthSquared() > (LL_JOINT_TRESHOLD_POS_OFFSET * LL_JOINT_TRESHOLD_POS_OFFSET))
+ {
+ // File contains multiple meshes with conflicting joint offsets
+ // preview may be incorrect, upload result might wary (depends onto
+ // mesh_id that hasn't been generated yet).
+ data.mHasConflicts = true;
+ }
+ data.mPosOverrides[model->getName()] = jointPos;
+
+ }
+ }
+ }
+ }
+ }
+
+ LLPanel *panel = mTabContainer->getPanelByName("overrides_panel");
+ S32 index = mTabContainer->getIndexForPanel(panel);
+ mTabContainer->enableTabButton(index, true);
+ LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list");
+
+ if (joints_list->isEmpty())
+ {
+ // Populate table
+ S32 conflicts = 0;
+ joint_override_data_map_t::iterator joint_iter = mJointOverrides[display_lod].begin();
+ joint_override_data_map_t::iterator joint_end = mJointOverrides[display_lod].end();
+ while (joint_iter != joint_end)
+ {
+ const std::string& listName = joint_iter->first;
+
+ LLScrollListItem::Params item_params;
+ item_params.value(listName);
+
+ LLScrollListCell::Params cell_params;
+ cell_params.font = LLFontGL::getFontSansSerif();
+ cell_params.value = listName;
+ if (joint_iter->second.mHasConflicts)
+ {
+ cell_params.color = LLColor4::orange;
+ conflicts++;
+ }
+
+ item_params.columns.add(cell_params);
+
+ joints_list->addRow(item_params, ADD_BOTTOM);
+ joint_iter++;
+ }
+ joints_list->selectFirstItem();
+
+ LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("conflicts_description");
+ joint_pos_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts));
+ joint_pos_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size()));
+ }
+}
+
+void LLFloaterModelPreview::hideOverridesTab()
+{
+ LLPanel *panel = mTabContainer->getPanelByName("overrides_panel");
+ S32 index = mTabContainer->getIndexForPanel(panel);
+ mTabContainer->enableTabButton(index, false);
+}
+
+//-----------------------------------------------------------------------------
+// addStringToLogTab()
+//-----------------------------------------------------------------------------
+void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash)
+{
+ if (str.empty())
+ {
+ return;
+ }
+
+ LLWString text = utf8str_to_wstring(str);
+ S32 add_text_len = text.length() + 1; // newline
+ S32 editor_max_len = mUploadLogText->getMaxTextLength();
+ if (add_text_len > editor_max_len)
+ {
+ return;
+ }
+
+ LLPanel* panel = mTabContainer->getPanelByName("logs_panel");
+ S32 index = mTabContainer->getIndexForPanel(panel);
+ mTabContainer->enableTabButton(index, true);
+
+ // Make sure we have space for new string
+ S32 editor_text_len = mUploadLogText->getLength();
+ while (editor_max_len < (editor_text_len + add_text_len))
+ {
+ editor_text_len -= mUploadLogText->removeFirstLine();
+ }
+
+ mUploadLogText->appendText(str, true);
+
+ if (flash && mTabContainer->getCurrentPanel() != panel)
+ {
+ mTabContainer->setTabPanelFlashing(panel, true);
+ }
+}
+
+//-----------------------------------------------------------------------------
// LLModelPreview
//-----------------------------------------------------------------------------
@@ -1225,12 +1597,13 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
, mLodsQuery()
, mLodsWithParsingError()
, mPelvisZOffset( 0.0f )
-, mLegacyRigValid( false )
+, mLegacyRigFlags( U32_MAX )
, mRigValidJointUpload( false )
, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
, mResetJoints( false )
, mModelNoErrors( true )
, mLastJointUpdate( false )
+, mHasDegenerate( false )
{
mNeedsUpdate = TRUE;
mCameraDistance = 0.f;
@@ -1645,8 +2018,14 @@ void LLModelPreview::rebuildUploadData()
LLQuaternion identity;
if (!bind_rot.isEqualEps(identity,0.01))
{
- LL_WARNS() << "non-identity bind shape rot. mat is " << high_lod_model->mSkinInfo.mBindShapeMatrix
- << " bind_rot " << bind_rot << LL_ENDL;
+ std::ostringstream out;
+ out << "non-identity bind shape rot. mat is ";
+ out << high_lod_model->mSkinInfo.mBindShapeMatrix;
+ out << " bind_rot ";
+ out << bind_rot;
+ LL_WARNS() << out.str() << LL_ENDL;
+
+ LLFloaterModelPreview::addStringToLog(out, false);
setLoadState( LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION );
}
}
@@ -1817,7 +2196,11 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::NUM_LODS - 1)
{
- LL_WARNS() << "Invalid level of detail: " << lod << LL_ENDL;
+ std::ostringstream out;
+ out << "Invalid level of detail: ";
+ out << lod;
+ LL_WARNS() << out.str() << LL_ENDL;
+ LLFloaterModelPreview::addStringToLog(out, true);
assert(lod >= LLModel::LOD_IMPOSTOR && lod < LLModel::NUM_LODS);
return;
}
@@ -2004,7 +2387,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
// Copy determinations about rig so UI will reflect them
//
setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload());
- setLegacyRigValid(mModelLoader->isLegacyRigValid());
+ setLegacyRigFlags(mModelLoader->getLegacyRigFlags());
mModelLoader->loadTextures() ;
@@ -2014,7 +2397,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
mBaseScene.clear();
bool skin_weights = false;
- bool joint_positions = false;
+ bool joint_overrides = false;
bool lock_scale_if_joint_position = false;
for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
@@ -2061,7 +2444,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty())
{
- joint_positions = true;
+ joint_overrides = true;
}
if (list_iter->mModel->mSkinInfo.mLockScaleIfJointPosition)
{
@@ -2084,12 +2467,19 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
fmp->childSetValue("upload_skin", true);
}
- if (joint_positions)
- {
+ if (joint_overrides)
+ {
+ fmp->enableViewOption("show_joint_overrides");
+ mViewOption["show_joint_overrides"] = true;
fmp->enableViewOption("show_joint_positions");
mViewOption["show_joint_positions"] = true;
fmp->childSetValue("upload_joints", true);
}
+ else
+ {
+ fmp->resetOverridesTab();
+ fmp->hideOverridesTab();
+ }
if (lock_scale_if_joint_position)
{
@@ -2194,7 +2584,12 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
if (importerDebug)
{
- LL_WARNS() << "Loded model name " << mModel[loaded_lod][idx]->mLabel << " for LOD " << loaded_lod << " doesn't match the base model. Renaming to " << name << LL_ENDL;
+ std::ostringstream out;
+ out << "Loded model name " << mModel[loaded_lod][idx]->mLabel;
+ out << " for LOD " << loaded_lod;
+ out << " doesn't match the base model. Renaming to " << name;
+ LL_WARNS() << out.str() << LL_ENDL;
+ LLFloaterModelPreview::addStringToLog(out, false);
}
mModel[loaded_lod][idx]->mLabel = name;
@@ -2218,7 +2613,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
mLoading = false;
if (mFMP)
{
- mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->set(FALSE);
if (!mBaseModel.empty())
{
const std::string& model_name = mBaseModel[0]->getName();
@@ -2352,7 +2746,10 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
// Allow LoD from -1 to LLModel::LOD_PHYSICS
if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
{
- LL_WARNS() << "Invalid level of detail: " << which_lod << LL_ENDL;
+ std::ostringstream out;
+ out << "Invalid level of detail: " << which_lod;
+ LL_WARNS() << out.str() << LL_ENDL;
+ LLFloaterModelPreview::addStringToLog(out, false);
assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS);
return;
}
@@ -2720,8 +3117,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
void LLModelPreview::updateStatusMessages()
{
+// bit mask values for physics errors. used to prevent overwrite of single line status
+// TODO: use this to provied multiline status
+ enum PhysicsError
+ {
+ NONE=0,
+ NOHAVOK=1,
+ DEGENERATE=2,
+ TOOMANYHULLS=4,
+ TOOMANYVERTSINHULL=8
+ };
+
assert_main_thread();
+ U32 has_physics_error{ PhysicsError::NONE }; // physics error bitmap
//triangle/vertex/submesh count for each mesh asset for each lod
std::vector<S32> tris[LLModel::NUM_LODS];
std::vector<S32> verts[LLModel::NUM_LODS];
@@ -2811,43 +3220,57 @@ void LLModelPreview::updateStatusMessages()
mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
}
- bool has_degenerate = false;
-
+ mHasDegenerate = false;
{//check for degenerate triangles in physics mesh
U32 lod = LLModel::LOD_PHYSICS;
const LLVector4a scale(0.5f);
- for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
+ for (U32 i = 0; i < mModel[lod].size() && !mHasDegenerate; ++i)
{ //for each model in the lod
if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty())
{ //no decomp exists
S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
- for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
+ for (S32 j = 0; j < cur_submeshes && !mHasDegenerate; ++j)
{ //for each submesh (face), add triangles and vertices to current total
LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
- for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; )
+ for (S32 k = 0; (k < face.mNumIndices) && !mHasDegenerate; )
{
- U16 index_a = face.mIndices[k+0];
- U16 index_b = face.mIndices[k+1];
- U16 index_c = face.mIndices[k+2];
-
- LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
- LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
- LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
+ U16 index_a = face.mIndices[k + 0];
+ U16 index_b = face.mIndices[k + 1];
+ U16 index_c = face.mIndices[k + 2];
- if (ll_is_degenerate(v1,v2,v3))
+ if (index_c == 0 && index_b == 0 && index_a == 0) // test in reverse as 3rd index is less likely to be 0 in a normal case
{
- has_degenerate = true;
+ LL_DEBUGS("MeshValidation") << "Empty placeholder triangle (3 identical index 0 verts) ignored" << LL_ENDL;
}
else
{
- k += 3;
+ LLVector4a v1; v1.setMul(face.mPositions[index_a], scale);
+ LLVector4a v2; v2.setMul(face.mPositions[index_b], scale);
+ LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);
+ if (ll_is_degenerate(v1, v2, v3))
+ {
+ mHasDegenerate = true;
+ }
}
+ k += 3;
}
}
}
}
}
+ // flag degenerates here rather than deferring to a MAV error later
+ mFMP->childSetVisible("physics_status_message_text", mHasDegenerate); //display or clear
+ auto degenerateIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
+ degenerateIcon->setVisible(mHasDegenerate);
+ if (mHasDegenerate)
+ {
+ has_physics_error |= PhysicsError::DEGENERATE;
+ mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_degenerate_triangles"));
+ LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Error");
+ degenerateIcon->setImage(img);
+ }
+
mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
std::string mesh_status_na = mFMP->getString("mesh_status_na");
@@ -2972,14 +3395,22 @@ void LLModelPreview::updateStatusMessages()
}
}
}
- mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
- LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
- physStatusIcon->setVisible(physExceededVertexLimit);
+
if (physExceededVertexLimit)
{
- mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
- LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
- physStatusIcon->setImage(img);
+ has_physics_error |= PhysicsError::TOOMANYVERTSINHULL;
+ }
+
+ if (!(has_physics_error & PhysicsError::DEGENERATE)){ // only update this field (incluides clearing it) if it is not already in use.
+ mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit);
+ LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon");
+ physStatusIcon->setVisible(physExceededVertexLimit);
+ if (physExceededVertexLimit)
+ {
+ mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded"));
+ LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning");
+ physStatusIcon->setImage(img);
+ }
}
if (getLoadState() >= LLModelLoader::ERROR_PARSING)
@@ -3009,11 +3440,15 @@ void LLModelPreview::updateStatusMessages()
}
}
- // Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics
- // current use of has_degenerate won't block upload permanently - later checks will restore the button
- if (!mModelNoErrors || has_degenerate)
+ if (!mModelNoErrors || mHasDegenerate)
{
mFMP->childDisable("ok_btn");
+ mFMP->childDisable("calculate_btn");
+ }
+ else
+ {
+ mFMP->childEnable("ok_btn");
+ mFMP->childEnable("calculate_btn");
}
if (mModelNoErrors && mLodsWithParsingError.empty())
@@ -3194,7 +3629,10 @@ void LLModelPreview::updateLodControls(S32 lod)
{
if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::LOD_HIGH)
{
- LL_WARNS() << "Invalid level of detail: " << lod << LL_ENDL;
+ std::ostringstream out;
+ out << "Invalid level of detail: " << lod;
+ LL_WARNS() << out.str() << LL_ENDL;
+ LLFloaterModelPreview::addStringToLog(out, false);
assert(lod >= LLModel::LOD_IMPOSTOR && lod <= LLModel::LOD_HIGH);
return;
}
@@ -3390,9 +3828,12 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
if (!vb->allocateBuffer(num_vertices, num_indices, TRUE))
{
// We are likely to crash due this failure, if this happens, find a way to gracefully stop preview
- LL_WARNS() << "Failed to allocate Vertex Buffer for model preview "
- << num_vertices << " vertices and "
- << num_indices << " indices" << LL_ENDL;
+ std::ostringstream out;
+ out << "Failed to allocate Vertex Buffer for model preview ";
+ out << num_vertices << " vertices and ";
+ out << num_indices << " indices";
+ LL_WARNS() << out.str() << LL_ENDL;
+ LLFloaterModelPreview::addStringToLog(out, true);
}
LLStrider<LLVector3> vertex_strider;
@@ -3540,8 +3981,21 @@ void LLModelPreview::loadedCallback(
LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
if (pPreview && !LLModelPreview::sIgnoreLoadedCallback)
{
- pPreview->loadModelCallback(lod);
- }
+ // Load loader's warnings into floater's log tab
+ const LLSD out = pPreview->mModelLoader->logOut();
+ LLSD::array_const_iterator iter_out = out.beginArray();
+ LLSD::array_const_iterator end_out = out.endArray();
+ for (; iter_out != end_out; ++iter_out)
+ {
+ if (iter_out->has("Message"))
+ {
+ LLFloaterModelPreview::addStringToLog(iter_out->get("Message"), *iter_out, true, pPreview->mModelLoader->mLod);
+ }
+ }
+ pPreview->mModelLoader->clearLog();
+ pPreview->loadModelCallback(lod); // removes mModelLoader in some cases
+ }
+
}
void LLModelPreview::stateChangedCallback(U32 state,void* opaque)
@@ -3618,11 +4072,13 @@ void LLModelPreview::addEmptyFace( LLModel* pTarget )
pTarget->setNumVolumeFaces( faceCnt+1 );
pTarget->setVolumeFaceData( faceCnt+1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices() );
-}
+}
//-----------------------------------------------------------------------------
// render()
//-----------------------------------------------------------------------------
+// Todo: we shouldn't be setting all those UI elements on render.
+// Note: Render happens each frame with skinned avatars
BOOL LLModelPreview::render()
{
assert_main_thread();
@@ -3633,16 +4089,32 @@ BOOL LLModelPreview::render()
bool use_shaders = LLGLSLShader::sNoFixedFunction;
bool edges = mViewOption["show_edges"];
+ bool joint_overrides = mViewOption["show_joint_overrides"];
bool joint_positions = mViewOption["show_joint_positions"];
bool skin_weight = mViewOption["show_skin_weight"];
bool textures = mViewOption["show_textures"];
bool physics = mViewOption["show_physics"];
+ // Extra configurability, to be exposed later as controls?
+ static LLCachedControl<LLColor4> canvas_col(gSavedSettings, "MeshPreviewCanvasColor");
+ static LLCachedControl<LLColor4> edge_col(gSavedSettings, "MeshPreviewEdgeColor");
+ static LLCachedControl<LLColor4> base_col(gSavedSettings, "MeshPreviewBaseColor");
+ static LLCachedControl<LLColor3> brightness(gSavedSettings, "MeshPreviewBrightnessColor");
+ static LLCachedControl<F32> edge_width(gSavedSettings, "MeshPreviewEdgeWidth");
+ static LLCachedControl<LLColor4> phys_edge_col(gSavedSettings, "MeshPreviewPhysicsEdgeColor");
+ static LLCachedControl<LLColor4> phys_fill_col(gSavedSettings, "MeshPreviewPhysicsFillColor");
+ static LLCachedControl<F32> phys_edge_width(gSavedSettings, "MeshPreviewPhysicsEdgeWidth");
+ static LLCachedControl<LLColor4> deg_edge_col(gSavedSettings, "MeshPreviewDegenerateEdgeColor");
+ static LLCachedControl<LLColor4> deg_fill_col(gSavedSettings, "MeshPreviewDegenerateFillColor");
+ static LLCachedControl<F32> deg_edge_width(gSavedSettings, "MeshPreviewDegenerateEdgeWidth");
+ static LLCachedControl<F32> deg_point_size(gSavedSettings, "MeshPreviewDegeneratePointSize");
+
S32 width = getWidth();
S32 height = getHeight();
LLGLSUIDefault def;
LLGLDisable no_blend(GL_BLEND);
+
LLGLEnable cull(GL_CULL_FACE);
LLGLDepthTest depth(GL_TRUE);
LLGLDisable fog(GL_FOG);
@@ -3662,8 +4134,7 @@ BOOL LLModelPreview::render()
gGL.pushMatrix();
gGL.loadIdentity();
- gGL.color4f(0.169f, 0.169f, 0.169f, 1.f);
-
+ gGL.color4fv(static_cast<LLColor4>(canvas_col).mV);
gl_rect_2d_simple( width, height );
gGL.matrixMode(LLRender::MM_PROJECTION);
@@ -3704,13 +4175,26 @@ BOOL LLModelPreview::render()
if (has_skin_weights && lodsReady())
{ //model has skin weights, enable view options for skin weights and joint positions
- if (fmp && isLegacyRigValid() )
- {
- fmp->enableViewOption("show_skin_weight");
- fmp->setViewOptionEnabled("show_joint_positions", skin_weight);
- mFMP->childEnable("upload_skin");
- mFMP->childSetValue("show_skin_weight", skin_weight);
- }
+ U32 flags = getLegacyRigFlags();
+ if (fmp)
+ {
+ if (flags == LEGACY_RIG_OK)
+ {
+ fmp->enableViewOption("show_skin_weight");
+ fmp->setViewOptionEnabled("show_joint_overrides", skin_weight);
+ fmp->setViewOptionEnabled("show_joint_positions", skin_weight);
+ mFMP->childEnable("upload_skin");
+ mFMP->childSetValue("show_skin_weight", skin_weight);
+ }
+ else if ((flags & LEGACY_RIG_FLAG_TOO_MANY_JOINTS) > 0)
+ {
+ mFMP->childSetVisible("skin_too_many_joints", true);
+ }
+ else if ((flags & LEGACY_RIG_FLAG_UNKNOWN_JOINT) > 0)
+ {
+ mFMP->childSetVisible("skin_unknown_joint", true);
+ }
+ }
}
else
{
@@ -3719,6 +4203,7 @@ BOOL LLModelPreview::render()
{
mViewOption["show_skin_weight"] = false;
fmp->disableViewOption("show_skin_weight");
+ fmp->disableViewOption("show_joint_overrides");
fmp->disableViewOption("show_joint_positions");
skin_weight = false;
@@ -3742,11 +4227,19 @@ BOOL LLModelPreview::render()
if (upload_skin && upload_joints)
{
mFMP->childEnable("lock_scale_if_joint_position");
+ if (fmp)
+ {
+ fmp->showOverridesTab();
+ }
}
else
{
mFMP->childDisable("lock_scale_if_joint_position");
mFMP->childSetValue("lock_scale_if_joint_position", false);
+ if (fmp)
+ {
+ fmp->hideOverridesTab();
+ }
}
//Only enable joint offsets if it passed the earlier critiquing
@@ -3777,10 +4270,9 @@ BOOL LLModelPreview::render()
if (skin_weight)
{
- target_pos = getPreviewAvatar()->getPositionAgent();
+ target_pos = getPreviewAvatar()->getPositionAgent() + offset;
z_near = 0.01f;
z_far = 1024.f;
- mCameraDistance = 16.f;
//render avatar previews every frame
refresh();
@@ -3798,8 +4290,9 @@ BOOL LLModelPreview::render()
LLQuaternion(mCameraYaw, LLVector3::z_axis);
LLQuaternion av_rot = camera_rot;
+ F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance;
LLViewerCamera::getInstance()->setOriginAndLookAt(
- target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera
+ target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera
LLVector3::z_axis, // up
target_pos); // point of interest
@@ -3811,8 +4304,7 @@ BOOL LLModelPreview::render()
stop_glerror();
gGL.pushMatrix();
- const F32 BRIGHTNESS = 0.9f;
- gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
+ gGL.color4fv(edge_col().mV);
const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
@@ -3897,16 +4389,15 @@ BOOL LLModelPreview::render()
}
else
{
- gGL.diffuseColor4f(1,1,1,1);
+ gGL.diffuseColor4fv(static_cast<LLColor4>(base_col).mV);
}
buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
-
+ gGL.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV);
if (edges)
{
- glLineWidth(3.f);
+ glLineWidth(edge_width);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -3919,10 +4410,9 @@ BOOL LLModelPreview::render()
if (physics)
{
glClear(GL_DEPTH_BUFFER_BIT);
-
- for (U32 i = 0; i < 2; i++)
+ for (U32 pass = 0; pass < 2; pass++)
{
- if (i == 0)
+ if (pass == 0)
{ //depth only pass
gGL.setColorMask(false, false);
}
@@ -3932,8 +4422,8 @@ BOOL LLModelPreview::render()
}
//enable alpha blending on second pass but not first pass
- LLGLState blend(GL_BLEND, i);
-
+ LLGLState blend(GL_BLEND, pass);
+
gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
@@ -3942,184 +4432,201 @@ BOOL LLModelPreview::render()
LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
- if (!model)
- {
- continue;
- }
+ if (!model)
+ {
+ continue;
+ }
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
+
+ gGL.multMatrix((GLfloat*)mat.mMatrix);
- gGL.multMatrix((GLfloat*) mat.mMatrix);
+ bool render_mesh = true;
+ LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+ if (decomp)
+ {
+ LLMutexLock(decomp->mMutex);
- bool render_mesh = true;
+ LLModel::Decomposition& physics = model->mPhysics;
- LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
- if (decomp)
+ if (!physics.mHull.empty())
{
- LLMutexLock(decomp->mMutex);
+ render_mesh = false;
- LLModel::Decomposition& physics = model->mPhysics;
-
- if (!physics.mHull.empty())
- {
- render_mesh = false;
+ if (physics.mMesh.empty())
+ { //build vertex buffer for physics mesh
+ gMeshRepo.buildPhysicsMesh(physics);
+ }
- if (physics.mMesh.empty())
- { //build vertex buffer for physics mesh
- gMeshRepo.buildPhysicsMesh(physics);
- }
-
- if (!physics.mMesh.empty())
- { //render hull instead of mesh
- for (U32 i = 0; i < physics.mMesh.size(); ++i)
+ if (!physics.mMesh.empty())
+ { //render hull instead of mesh
+ for (U32 i = 0; i < physics.mMesh.size(); ++i)
+ {
+ if (explode > 0.f)
{
- if (explode > 0.f)
- {
- gGL.pushMatrix();
+ gGL.pushMatrix();
- LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters;
- offset *= explode;
+ LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters;
+ offset *= explode;
- gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
- }
+ gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
+ }
- static std::vector<LLColor4U> hull_colors;
+ static std::vector<LLColor4U> hull_colors;
- if (i+1 >= hull_colors.size())
- {
- hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128));
- }
+ if (i + 1 >= hull_colors.size())
+ {
+ hull_colors.push_back(LLColor4U(rand() % 128 + 127, rand() % 128 + 127, rand() % 128 + 127, 128));
+ }
- gGL.diffuseColor4ubv(hull_colors[i].mV);
- LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+ gGL.diffuseColor4ubv(hull_colors[i].mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
- if (explode > 0.f)
- {
- gGL.popMatrix();
- }
+ if (explode > 0.f)
+ {
+ gGL.popMatrix();
}
}
}
}
-
- if (render_mesh)
+ }
+
+ if (render_mesh)
+ {
+ if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
{
- if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
- {
- genBuffers(LLModel::LOD_PHYSICS, false);
- }
+ genBuffers(LLModel::LOD_PHYSICS, false);
+ }
- U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+ U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+ if (pass > 0){
for (U32 i = 0; i < num_models; ++i)
{
LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f);
+ gGL.diffuseColor4fv(phys_fill_col().mV);
buffer->setBuffer(type_mask & buffer->getTypeMask());
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
-
- gGL.diffuseColor3f(1.f, 1.f, 0.f);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0);
- glLineWidth(2.f);
+ gGL.diffuseColor4fv(phys_edge_col().mV);
+ glLineWidth(phys_edge_width);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glLineWidth(1.f);
}
}
-
- gGL.popMatrix();
}
- glLineWidth(3.f);
- glPointSize(8.f);
- gPipeline.enableLightsFullbright(LLColor4::white);
- //show degenerate triangles
- LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
- LLGLDisable cull(GL_CULL_FACE);
- gGL.diffuseColor4f(1.f,0.f,0.f,1.f);
- const LLVector4a scale(0.5f);
+ gGL.popMatrix();
+ }
- for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
+ // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks]
+ if (pass > 0 && mHasDegenerate)
{
- LLModelInstance& instance = *iter;
-
- LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
-
- if (!model)
+ glLineWidth(deg_edge_width);
+ glPointSize(deg_point_size);
+ //show degenerate triangles
+ LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+ LLGLDisable cull(GL_CULL_FACE);
+ const LLVector4a scale(0.5f);
+
+ for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)
{
- continue;
- }
+ LLModelInstance& instance = *iter;
- gGL.pushMatrix();
- LLMatrix4 mat = instance.mTransform;
+ LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS];
- gGL.multMatrix((GLfloat*) mat.mMatrix);
+ if (!model)
+ {
+ continue;
+ }
+ gGL.pushMatrix();
+ LLMatrix4 mat = instance.mTransform;
- LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
- if (decomp)
- {
- LLMutexLock(decomp->mMutex);
+ gGL.multMatrix((GLfloat*)mat.mMatrix);
- LLModel::Decomposition& physics = model->mPhysics;
- if (physics.mHull.empty())
+ LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread;
+ if (decomp)
{
- if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
- {
- genBuffers(LLModel::LOD_PHYSICS, false);
- }
-
- for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i)
- {
- LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i];
+ LLMutexLock(decomp->mMutex);
- buffer->setBuffer(type_mask & buffer->getTypeMask());
+ LLModel::Decomposition& physics = model->mPhysics;
- LLStrider<LLVector3> pos_strider;
- buffer->getVertexStrider(pos_strider, 0);
- LLVector4a* pos = (LLVector4a*) pos_strider.get();
-
- LLStrider<U16> idx;
- buffer->getIndexStrider(idx, 0);
+ if (physics.mHull.empty())
+ {
+ if (mVertexBuffer[LLModel::LOD_PHYSICS].empty())
+ {
+ genBuffers(LLModel::LOD_PHYSICS, false);
+ }
- for (U32 i = 0; i < buffer->getNumIndices(); i += 3)
+ auto num_degenerate = 0;
+ auto num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size();
+ for (U32 v = 0; v < num_models; ++v)
{
- LLVector4a v1; v1.setMul(pos[*idx++], scale);
- LLVector4a v2; v2.setMul(pos[*idx++], scale);
- LLVector4a v3; v3.setMul(pos[*idx++], scale);
+ LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v];
+ if(buffer->getNumVerts() < 3)continue;
+
+ buffer->setBuffer(type_mask & buffer->getTypeMask());
+
+ LLStrider<LLVector3> pos_strider;
+ buffer->getVertexStrider(pos_strider, 0);
+ LLVector4a* pos = (LLVector4a*)pos_strider.get();
- if (ll_is_degenerate(v1,v2,v3))
+ LLStrider<U16> idx;
+ buffer->getIndexStrider(idx, 0);
+
+ LLVector4a v1, v2, v3;
+ for (U32 indices_offset = 0; indices_offset < buffer->getNumIndices(); indices_offset += 3)
{
- buffer->draw(LLRender::LINE_LOOP, 3, i);
- buffer->draw(LLRender::POINTS, 3, i);
+ v1.setMul(pos[*idx++], scale);
+ v2.setMul(pos[*idx++], scale);
+ v3.setMul(pos[*idx++], scale);
+
+ if (ll_is_degenerate(v1, v2, v3))
+ {
+ num_degenerate++;
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ gGL.diffuseColor3fv(deg_edge_col().mV);
+ buffer->drawRange(LLRender::TRIANGLES, 0, 2, 3, indices_offset);
+ buffer->drawRange(LLRender::POINTS, 0, 2, 3, indices_offset);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ gGL.diffuseColor3fv(deg_fill_col().mV);
+ buffer->drawRange(LLRender::TRIANGLES, 0, 2, 3, indices_offset);
+ }
}
}
}
}
- }
- gGL.popMatrix();
+ gGL.popMatrix();
+ }
+ glLineWidth(1.f);
+ glPointSize(1.f);
+ gPipeline.enableLightsPreview();
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
- glLineWidth(1.f);
- glPointSize(1.f);
- gPipeline.enableLightsPreview();
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
}
}
}
else
{
target_pos = getPreviewAvatar()->getPositionAgent();
+ getPreviewAvatar()->clearAttachmentOverrides(); // removes pelvis fixup
+ LLUUID fake_mesh_id;
+ fake_mesh_id.generate();
+ getPreviewAvatar()->addPelvisFixup(mPelvisZOffset, fake_mesh_id);
+ bool pelvis_recalc = false;
LLViewerCamera::getInstance()->setOriginAndLookAt(
- target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera
+ target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera
LLVector3::z_axis, // up
target_pos); // point of interest
@@ -4132,6 +4639,51 @@ BOOL LLModelPreview::render()
if (!model->mSkinWeights.empty())
{
+ const LLMeshSkinInfo *skin = &model->mSkinInfo;
+ LLSkinningUtil::initJointNums(&model->mSkinInfo, getPreviewAvatar());// inits skin->mJointNums if nessesary
+ U32 count = LLSkinningUtil::getMeshJointCount(skin);
+
+ if (joint_overrides && skin->mAlternateBindMatrix.size() > 0)
+ {
+ // mesh_id is used to determine which mesh gets to
+ // set the joint offset, in the event of a conflict. Since
+ // we don't know the mesh id yet, we can't guarantee that
+ // joint offsets will be applied with the same priority as
+ // in the uploaded model. If the file contains multiple
+ // meshes with conflicting joint offsets, preview may be
+ // incorrect.
+ LLUUID fake_mesh_id;
+ fake_mesh_id.generate();
+ for (U32 j = 0; j < count; ++j)
+ {
+ LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]);
+ if (joint)
+ {
+ const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation();
+ if (joint->aboveJointPosThreshold(jointPos))
+ {
+ bool override_changed;
+ joint->addAttachmentPosOverride(jointPos, fake_mesh_id, "model", override_changed);
+
+ if (override_changed)
+ {
+ //If joint is a pelvis then handle old/new pelvis to foot values
+ if (joint->getName() == "mPelvis")// or skin->mJointNames[j]
+ {
+ pelvis_recalc = true;
+ }
+ }
+ if (skin->mLockScaleIfJointPosition)
+ {
+ // Note that unlike positions, there's no threshold check here,
+ // just a lock at the default value.
+ joint->addAttachmentScaleOverride(joint->getDefaultScale(), fake_mesh_id, "model");
+ }
+ }
+ }
+ }
+ }
+
for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i)
{
LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
@@ -4149,10 +4701,9 @@ BOOL LLModelPreview::render()
//build matrix palette
LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
- const LLMeshSkinInfo *skin = &model->mSkinInfo;
- U32 count = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count,
skin, getPreviewAvatar());
+
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
U32 max_joints = LLSkinningUtil::getMaxJointCount();
@@ -4192,11 +4743,11 @@ BOOL LLModelPreview::render()
}
buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
- gGL.diffuseColor3f(0.4f, 0.4f, 0.4f);
if (edges)
{
- glLineWidth(3.f);
+ gGL.diffuseColor4fv(edge_col().mV);
+ glLineWidth(edge_width);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -4222,6 +4773,11 @@ BOOL LLModelPreview::render()
}
}
+ if (pelvis_recalc)
+ {
+ // size/scale recalculation
+ getPreviewAvatar()->postPelvisSetRecalc();
+ }
}
}
@@ -4259,14 +4815,17 @@ void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians)
void LLModelPreview::zoom(F32 zoom_amt)
{
F32 new_zoom = mCameraZoom+zoom_amt;
-
- mCameraZoom = llclamp(new_zoom, 1.f, 10.f);
+ // TODO: stop clamping in render
+ static LLCachedControl<F32> zoom_limit(gSavedSettings, "MeshPreviewZoomLimit");
+ mCameraZoom = llclamp(new_zoom, 1.f, zoom_limit());
}
void LLModelPreview::pan(F32 right, F32 up)
{
- mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f);
- mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f);
+ bool skin_weight = mViewOption["show_skin_weight"];
+ F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance;
+ mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * camera_distance / mCameraZoom, -1.f, 1.f);
+ mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * camera_distance / mCameraZoom, -1.f, 1.f);
}
void LLModelPreview::setPreviewLOD(S32 lod)
@@ -4281,12 +4840,6 @@ void LLModelPreview::setPreviewLOD(S32 lod)
combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order
mFMP->childSetValue("lod_file_" + lod_name[mPreviewLOD], mLODFile[mPreviewLOD]);
- 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");
@@ -4299,6 +4852,13 @@ void LLModelPreview::setPreviewLOD(S32 lod)
mFMP->childSetColor(lod_triangles_name[i], color);
mFMP->childSetColor(lod_vertices_name[i], color);
}
+
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)mFMP;
+ if (fmp)
+ {
+ // make preview repopulate tab
+ fmp->clearOverridesTab();
+ }
}
refresh();
updateStatusMessages();
@@ -4316,12 +4876,16 @@ void LLFloaterModelPreview::onReset(void* user_data)
{
assert_main_thread();
+
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;
fmp->childDisable("reset_btn");
+ fmp->clearLogTab();
+ fmp->resetOverridesTab();
LLModelPreview* mp = fmp->mModelPreview;
std::string filename = mp->mLODFile[LLModel::LOD_HIGH];
fmp->resetDisplayOptions();
+ fmp->resetUploadOptions();
//reset model preview
fmp->initModelPreview();
@@ -4335,6 +4899,7 @@ void LLFloaterModelPreview::onUpload(void* user_data)
assert_main_thread();
LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data;
+ mp->clearLogTab();
mp->mUploadBtn->setEnabled(false);
@@ -4475,11 +5040,15 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
{
childSetTextArg("upload_fee", "[FEE]", tbd);
}
- childSetTextArg("price_breakdown", "[STREAMING]", tbd);
- childSetTextArg("price_breakdown", "[PHYSICS]", tbd);
- childSetTextArg("price_breakdown", "[INSTANCES]", tbd);
- childSetTextArg("price_breakdown", "[TEXTURES]", tbd);
- childSetTextArg("price_breakdown", "[MODEL]", tbd);
+ std::string dashes = hasString("--") ? getString("--") : "--";
+ childSetTextArg("price_breakdown", "[STREAMING]", dashes);
+ childSetTextArg("price_breakdown", "[PHYSICS]", dashes);
+ childSetTextArg("price_breakdown", "[INSTANCES]", dashes);
+ childSetTextArg("price_breakdown", "[TEXTURES]", dashes);
+ childSetTextArg("price_breakdown", "[MODEL]", dashes);
+ childSetTextArg("physics_breakdown", "[PCH]", dashes);
+ childSetTextArg("physics_breakdown", "[PM]", dashes);
+ childSetTextArg("physics_breakdown", "[PHU]", dashes);
}
}
@@ -4506,6 +5075,44 @@ void LLFloaterModelPreview::resetDisplayOptions()
}
}
+void LLFloaterModelPreview::resetUploadOptions()
+{
+ childSetValue("import_scale", 1);
+ childSetValue("pelvis_offset", 0);
+ childSetValue("physics_explode", 0);
+ childSetValue("physics_file", "");
+ childSetVisible("Retain%", false);
+ childSetVisible("Retain%_label", false);
+ childSetVisible("Detail Scale", true);
+ childSetVisible("Detail Scale label", true);
+
+ getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE);
+ for (S32 lod = 0; lod < NUM_LOD - 1; ++lod)
+ {
+ getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE);
+ childSetValue("lod_file_" + lod_name[lod], "");
+ }
+
+ for(auto& p : mDefaultDecompParams)
+ {
+ std::string ctrl_name(p.first);
+ LLUICtrl* ctrl = getChild<LLUICtrl>(ctrl_name);
+ if (ctrl)
+ {
+ ctrl->setValue(p.second);
+ }
+ }
+ getChild<LLComboBox>("physics_lod_combo")->setCurrentByIndex(0);
+ getChild<LLComboBox>("Cosine%")->setCurrentByIndex(0);
+}
+
+void LLFloaterModelPreview::clearLogTab()
+{
+ mUploadLogText->clear();
+ LLPanel* panel = mTabContainer->getPanelByName("logs_panel");
+ mTabContainer->setTabPanelFlashing(panel, false);
+}
+
void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url)
{
mModelPhysicsFee = result;
@@ -4529,6 +5136,16 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
childSetTextArg("price_breakdown", "[INSTANCES]", llformat("%d", result["upload_price_breakdown"]["mesh_instance"].asInteger()));
childSetTextArg("price_breakdown", "[TEXTURES]", llformat("%d", result["upload_price_breakdown"]["texture"].asInteger()));
childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));
+
+ childSetTextArg("physics_breakdown", "[PCH]", llformat("%0.3f", result["model_physics_cost"]["hull"].asReal()));
+ childSetTextArg("physics_breakdown", "[PM]", llformat("%0.3f", result["model_physics_cost"]["mesh"].asReal()));
+ childSetTextArg("physics_breakdown", "[PHU]", llformat("%0.3f", result["model_physics_cost"]["decomposition"].asReal()));
+ childSetTextArg("streaming_breakdown", "[STR_TOTAL]", llformat("%d", result["streaming_cost"].asInteger()));
+ childSetTextArg("streaming_breakdown", "[STR_HIGH]", llformat("%d", result["streaming_params"]["high_lod"].asInteger()));
+ childSetTextArg("streaming_breakdown", "[STR_MED]", llformat("%d", result["streaming_params"]["medium_lod"].asInteger()));
+ childSetTextArg("streaming_breakdown", "[STR_LOW]", llformat("%d", result["streaming_params"]["low_lod"].asInteger()));
+ childSetTextArg("streaming_breakdown", "[STR_LOWEST]", llformat("%d", result["streaming_params"]["lowest_lod"].asInteger()));
+
childSetVisible("upload_fee", true);
childSetVisible("price_breakdown", true);
mUploadBtn->setEnabled(isModelUploadAllowed());
@@ -4536,7 +5153,11 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()
void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason, const LLSD& result)
{
- LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL;
+ std::ostringstream out;
+ out << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status;
+ out << " : " << reason << ")";
+ LL_WARNS() << out.str() << LL_ENDL;
+ LLFloaterModelPreview::addStringToLog(out, false);
doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true));
if (result.has("upload_price"))