diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 74ad82f08a..d2b3643055 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -429,7 +429,7 @@ void showJointScaleOverrides( const LLJoint& joint, const std::string& note, con bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const { LLVector3 diff = pos - getDefaultPosition(); - const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm + const F32 max_joint_pos_offset = LL_JOINT_TRESHOLD_POS_OFFSET; // 0.1 mm return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset; } @@ -532,7 +532,7 @@ void LLJoint::clearAttachmentPosOverrides() // getAllAttachmentPosOverrides() //-------------------------------------------------------------------- void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, - std::set& distinct_pos_overrides) + std::set& distinct_pos_overrides) const { num_pos_overrides = m_attachmentPosOverrides.count(); LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); @@ -546,7 +546,7 @@ void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, // getAllAttachmentScaleOverrides() //-------------------------------------------------------------------- void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides, - std::set& distinct_scale_overrides) + std::set& distinct_scale_overrides) const { num_scale_overrides = m_attachmentScaleOverrides.count(); LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index f408d25be6..724c703aa2 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -79,6 +79,8 @@ const U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2); const S32 LL_CHARACTER_MAX_PRIORITY = 7; const F32 LL_MAX_PELVIS_OFFSET = 5.f; +const F32 LL_JOINT_TRESHOLD_POS_OFFSET = 0.0001f; //0.1 mm + class LLVector3OverrideMap { public: @@ -313,9 +315,9 @@ public: void showAttachmentScaleOverrides(const std::string& av_info) const; void getAllAttachmentPosOverrides(S32& num_pos_overrides, - std::set& distinct_pos_overrides); + std::set& distinct_pos_overrides) const; void getAllAttachmentScaleOverrides(S32& num_scale_overrides, - std::set& distinct_scale_overrides); + std::set& distinct_scale_overrides) const; // These are used in checks of whether a pos/scale override is considered significant. bool aboveJointPosThreshold(const LLVector3& pos) const; diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index ac860ad6ca..33671b9bd2 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -139,7 +139,7 @@ LLModelLoader::LLModelLoader( , mStateCallback(state_cb) , mOpaqueData(opaque_userdata) , mRigValidJointUpload(true) -, mLegacyRigValid(true) +, mLegacyRigFlags(0) , mNoNormalize(false) , mNoOptimize(false) , mCacheOnlyHitIfRigged(false) @@ -148,6 +148,7 @@ LLModelLoader::LLModelLoader( { assert_main_thread(); sActiveLoaderList.push_back(this) ; + mWarningsArray = LLSD::emptyArray(); } LLModelLoader::~LLModelLoader() @@ -158,6 +159,7 @@ LLModelLoader::~LLModelLoader() void LLModelLoader::run() { + mWarningsArray.clear(); doLoadModel(); doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); } @@ -402,7 +404,7 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector &jointListFromAsset ) +U32 LLModelLoader::determineRigLegacyFlags( const std::vector &jointListFromAsset ) { //No joints in asset if ( jointListFromAsset.size() == 0 ) @@ -441,7 +440,12 @@ bool LLModelLoader::isRigLegacy( const std::vector &jointListFromAs { LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL; LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL; - return false; + LLSD args; + args["Message"] = "TooManyJoint"; + args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size()); + args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh); + mWarningsArray.append(args); + return LEGACY_RIG_FLAG_TOO_MANY_JOINTS; } // Unknown joints in asset @@ -452,16 +456,24 @@ bool LLModelLoader::isRigLegacy( const std::vector &jointListFromAs if (mJointMap.find(*it)==mJointMap.end()) { LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL; + LLSD args; + args["Message"] = "UnrecognizedJoint"; + args["[NAME]"] = *it; + mWarningsArray.append(args); unknown_joint_count++; } } if (unknown_joint_count>0) { LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL; - return false; + LLSD args; + args["Message"] = "UnknownJoints"; + args["[COUNT]"] = LLSD::Integer(unknown_joint_count); + mWarningsArray.append(args); + return LEGACY_RIG_FLAG_UNKNOWN_JOINT; } - return true; + return LEGACY_RIG_OK; } //----------------------------------------------------------------------------- // isRigSuitableForJointPositionUpload() diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index fb67947e2d..a67c39252c 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -42,6 +42,10 @@ typedef std::deque JointNameSet; const S32 SLM_SUPPORTED_VERSION = 3; const S32 NUM_LOD = 4; +const U32 LEGACY_RIG_OK = 0; +const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1; +const U32 LEGACY_RIG_FLAG_UNKNOWN_JOINT = 2; + class LLModelLoader : public LLThread { public: @@ -166,7 +170,7 @@ public: void critiqueRigForUploadApplicability( const std::vector &jointListFromAsset ); //Determines if a rig is a legacy from the joint list - bool isRigLegacy( const std::vector &jointListFromAsset ); + U32 determineRigLegacyFlags( const std::vector &jointListFromAsset ); //Determines if a rig is suitable for upload bool isRigSuitableForJointPositionUpload( const std::vector &jointListFromAsset ); @@ -174,8 +178,9 @@ public: const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } - const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } - void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; } + const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; } + U32 getLegacyRigFlags() const { return mLegacyRigFlags; } + void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; } //----------------------------------------------------------------------------- // isNodeAJoint() @@ -185,6 +190,9 @@ public: return name != NULL && mJointMap.find(name) != mJointMap.end(); } + const LLSD logOut() const { return mWarningsArray; } + void clearLog() { mWarningsArray.clear(); } + protected: // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup std::vector< std::string > toStringVector( std::vector< JointKey > const &aIn ) const @@ -205,13 +213,15 @@ protected: void* mOpaqueData; bool mRigValidJointUpload; - bool mLegacyRigValid; + U32 mLegacyRigFlags; bool mNoNormalize; bool mNoOptimize; JointTransformMap mJointTransformMap; + LLSD mWarningsArray; // preview floater will pull logs from here + static std::list sActiveLoaderList; static bool isAlive(LLModelLoader* loader) ; }; diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index e07435886a..2eacd622f7 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -770,6 +770,11 @@ void LLButton::draw() { glow_color = highlighting_color; } + else + { + // will fade from highlight color + glow_color = flash_color; + } } } diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index e4420bb1dc..b32b698388 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -207,6 +207,7 @@ public: void setFlashing( bool b, bool force_flashing = false ); BOOL getFlashing() const { return mFlashing; } LLFlashTimer* getFlashTimer() {return mFlashingTimer;} + void setFlashColor(const LLUIColor &color) { mFlashBgColor = color; }; void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } LLFontGL::HAlign getHAlign() const { return mHAlign; } diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 3d7afdb1a7..01a517f6aa 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -136,6 +136,7 @@ LLScrollListCtrl::Params::Params() primary_sort_only("primary_sort_only", false), // Option to only sort by one column mouse_wheel_opaque("mouse_wheel_opaque", false), commit_on_keyboard_movement("commit_on_keyboard_movement", true), + commit_on_selection_change("commit_on_selection_change", false), heading_height("heading_height"), page_lines("page_lines", 0), background_visible("background_visible"), @@ -166,7 +167,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) mMaxSelectable(0), mAllowKeyboardMovement(true), mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), - mCommitOnSelectionChange(false), + mCommitOnSelectionChange(p.commit_on_selection_change), mSelectionChanged(false), mNeedsScroll(false), mCanSelect(true), diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 40eaa4e9d4..602e087e86 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -97,6 +97,7 @@ public: // behavioral flags Optional multi_select, commit_on_keyboard_movement, + commit_on_selection_change, mouse_wheel_opaque; // display flags diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index a5a49dd835..aa82712645 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -39,7 +39,6 @@ #include "llfloater.h" #include "lltrans.h" - //---------------------------------------------------------------------------- // Implementation Notes: @@ -224,6 +223,7 @@ LLTabContainer::Params::Params() last_tab("last_tab"), use_custom_icon_ctrl("use_custom_icon_ctrl", false), open_tabs_on_drag_and_drop("open_tabs_on_drag_and_drop", false), + enable_tabs_flashing("enable_tabs_flashing", false), tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), use_ellipses("use_ellipses"), label_shadow("label_shadow",false), // no drop shadowed labels by default -Zi @@ -269,6 +269,7 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), mTabIconCtrlPad(p.tab_icon_ctrl_pad), mUseTabEllipses(p.use_ellipses), + mEnableTabsFlashing(p.enable_tabs_flashing), mDropShadowedText(p.label_shadow) // support for drop shadowed tab labels -Zi { // AO: Treat the IM tab container specially @@ -1248,6 +1249,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) p.pad_right(2); } + // inits flash timer + p.button_flash_enable = mEnableTabsFlashing; + // Enable tab flashing p.button_flash_enable(LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableButtonFlashing")); p.button_flash_count(LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount")); @@ -1803,6 +1807,16 @@ void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state ) } } +void LLTabContainer::setTabPanelFlashing(LLPanel* child, BOOL state, LLUIColor color) +{ + LLTabTuple* tuple = getTabByPanel(child); + if (tuple) + { + tuple->mButton->setFlashColor(color); + tuple->mButton->setFlashing(state); + } +} + void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const LLColor4& color) { LLTabTuple* tuple = getTabByPanel(child); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 1209ffd412..e61c5b49c1 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -123,6 +123,11 @@ public: * Open tabs on hover in drag and drop situations */ Optional open_tabs_on_drag_and_drop; + + /** + * Enable tab flashing + */ + Optional enable_tabs_flashing; /** * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) @@ -215,6 +220,7 @@ public: BOOL getTabPanelFlashing(LLPanel* child); void setTabPanelFlashing(LLPanel* child, BOOL state); + void setTabPanelFlashing(LLPanel* child, BOOL state, LLUIColor color); void setTabImage(LLPanel* child, std::string img_name, const LLColor4& color = LLColor4::white); void setTabImage(LLPanel* child, const LLUUID& img_id, const LLColor4& color = LLColor4::white); void setTabImage(LLPanel* child, LLIconCtrl* icon); @@ -343,6 +349,7 @@ private: bool mCustomIconCtrlUsed; bool mOpenTabsOnDragAndDrop; + bool mEnableTabsFlashing; S32 mTabIconCtrlPad; bool mUseTabEllipses; }; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index a17170b3a0..987635822a 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2426,6 +2426,18 @@ void LLTextBase::needsReflow(S32 index) // [/SL:KB] } +S32 LLTextBase::removeFirstLine() +{ + if (!mLineInfoList.empty()) + { + S32 length = getLineEnd(0); + deselect(); + removeStringNoUndo(0, length); + return length; + } + return 0; +} + void LLTextBase::appendLineBreakSegment(const LLStyle::Params& style_params) { segment_vec_t segments; diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 6ffbe0baad..160861d777 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -435,8 +435,7 @@ public: virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style virtual std::string getText() const; void setMaxTextLength(S32 length) { mMaxTextByteLength = length; } - // Getter for mMaxTextByteLength - S32 getMaxTextLength() const { return mMaxTextByteLength; } + S32 getMaxTextLength() { return mMaxTextByteLength; } // wide-char versions void setWText(const LLWString& text); @@ -465,6 +464,7 @@ public: S32 getLength() const { return getWText().length(); } S32 getLineCount() const { return mLineInfoList.size(); } + S32 removeFirstLine(); // returns removed length void addDocumentChild(LLView* view); void removeDocumentChild(LLView* view); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 27fc60be75..d560e5a89e 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -75,6 +75,7 @@ #include "llsdserialize.h" #include "llsliderctrl.h" #include "llspinctrl.h" +#include "lltabcontainer.h" #include "lltoggleablemenu.h" #include "lltrans.h" #include "llvfile.h" @@ -82,6 +83,7 @@ #include "llcallbacklist.h" #include "llviewerobjectlist.h" #include "llanimationstates.h" +#include "llviewertexteditor.h" #include "llviewernetwork.h" #include "llviewershadermgr.h" // @@ -110,6 +112,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); @@ -266,7 +270,10 @@ 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), +mAvatarTabIndex(0) { sInstance = this; mLastMouseX = 0; @@ -335,7 +342,8 @@ BOOL LLFloaterModelPreview::postBuild() getChild("show_edges")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild("show_physics")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild("show_textures")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); - getChild("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); + getChild("show_skin_weight")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onShowSkinWeightChecked, this, _1)); + getChild("show_joint_overrides")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild("show_joint_positions")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); getChild("show_uv_guide")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); // - Add UV guide overlay to pmesh preview @@ -343,6 +351,13 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_joints"); childDisable("lock_scale_if_joint_position"); + childSetVisible("skin_too_many_joints", false); + childSetVisible("skin_unknown_joint", false); + + childSetVisible("warning_title", false); + childSetVisible("warning_message", false); + childSetVisible("status", false); + initDecompControls(); LLView* preview_panel = getChild("preview_panel"); @@ -432,6 +447,12 @@ BOOL LLFloaterModelPreview::postBuild() mUploadBtn = getChild("ok_btn"); mCalculateBtn = getChild("calculate_btn"); + mUploadLogText = getChild("log_text"); + mTabContainer = getChild("import_tab"); + + LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + mAvatarTabIndex = mTabContainer->getIndexForPanel(panel); + panel->getChild("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); if (LLConvexDecomposition::getInstance() != NULL) { @@ -501,6 +522,15 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) toggleCalculateButton(true); } +void LLFloaterModelPreview::onShowSkinWeightChecked(LLUICtrl* ctrl) +{ + if (mModelPreview) + { + mModelPreview->mCameraOffset.clearVec(); + onViewOptionChecked(ctrl); + } +} + void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) { if (mModelPreview) @@ -585,6 +615,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(); @@ -611,6 +643,82 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadBtn->setEnabled(false); } +void populate_list_with_map(LLScrollListCtrl *list, const std::map &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::const_iterator iter = vector_map.begin(); + std::map::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("avatar_panel"); + LLScrollListCtrl *joints_list = panel->getChild("joints_list"); + LLScrollListCtrl *joints_pos = panel->getChild("pos_overrides_list"); + LLScrollListCtrl *joints_scale = panel->getChild("scale_overrides_list"); + LLTextBox *joint_pos_descr = panel->getChild("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); + mSelectedJointName = label; + } + else + { + // temporary value (shouldn't happen) + std::string label = "mPelvis"; + joint_pos_descr->setTextArg("[JOINT]", label); + mSelectedJointName.clear(); + } + + // Note: We can make a version of renderBones() to highlight selected joint +} + void LLFloaterModelPreview::onDescriptionKeystroke(LLUICtrl* ctrl) { // Workaround for SL-4186, server doesn't allow name changes after 'calculate' stage @@ -762,7 +870,6 @@ void LLFloaterModelPreview::draw3dPreview() gGL.getTexUnit(0)->bind(mModelPreview); - LLView* preview_panel = getChild("preview_panel"); if (!preview_panel) @@ -1383,6 +1490,215 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl gViewerWindow->showCursor(); } +//----------------------------------------------------------------------------- +// 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::clearAvatarTab() +{ + LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + LLScrollListCtrl *joints_list = panel->getChild("joints_list"); + joints_list->deleteAllItems(); + LLScrollListCtrl *joints_pos = panel->getChild("pos_overrides_list"); + joints_pos->deleteAllItems(); mSelectedJointName.clear(); + + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mJointOverrides[i].clear(); + } + + LLTextBox *joint_total_descr = panel->getChild("conflicts_description"); + joint_total_descr->setTextArg("[CONFLICTS]", llformat("%d", 0)); + joint_total_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", 0)); + + + LLTextBox *joint_pos_descr = panel->getChild("pos_overrides_descr"); + joint_pos_descr->setTextArg("[JOINT]", std::string("mPelvis")); // Might be better to hide it +} + +void LLFloaterModelPreview::updateAvatarTab() +{ + S32 display_lod = mModelPreview->mPreviewLOD; + if (mModelPreview->mModel[display_lod].empty()) + { + mSelectedJointName.clear(); + 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(); + // Query by JointKey rather than just a string, the key can be a U32 index for faster lookup + //LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; + LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j].mName]; + 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("avatar_panel"); + LLScrollListCtrl *joints_list = panel->getChild("joints_list"); + + if (joints_list->isEmpty()) + { + // Populate table + + std::map joint_alias_map; + mModelPreview->getJointAliases(joint_alias_map); + + 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_alias_map.find(listName) == joint_alias_map.end()) + { + // Missing names + cell_params.color = LLColor4::red; + } + if (joint_iter->second.mHasConflicts) + { + // Conflicts + cell_params.color = LLColor4::orange; + conflicts++; + } + + item_params.columns.add(cell_params); + + joints_list->addRow(item_params, ADD_BOTTOM); + joint_iter++; + } + joints_list->selectFirstItem(); + LLScrollListItem *selected = joints_list->getFirstSelected(); + if (selected) + { + mSelectedJointName = selected->getValue().asString(); + } + + LLTextBox *joint_conf_descr = panel->getChild("conflicts_description"); + joint_conf_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts)); + joint_conf_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size())); + } +} + +//----------------------------------------------------------------------------- +// 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"); + + // 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) + { + // This will makes colors pale due to "glow_type = LLRender::BT_ALPHA" + // So instead of using "MenuItemFlashBgColor" added stronger color + static LLUIColor sFlashBgColor(LLColor4U(255, 99, 0)); + mTabContainer->setTabPanelFlashing(panel, true, sFlashBgColor); + } +} + //----------------------------------------------------------------------------- // LLModelPreview //----------------------------------------------------------------------------- @@ -1392,7 +1708,7 @@ 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 ) @@ -1824,8 +2140,14 @@ void LLModelPreview::rebuildUploadData() LLQuaternion identity; if (!bind_rot.isEqualEps(identity,0.01f)) { - 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 ); } } @@ -2000,7 +2322,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; } @@ -2187,7 +2513,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() ; @@ -2197,7 +2523,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) @@ -2244,7 +2570,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) { @@ -2267,12 +2593,18 @@ 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->clearAvatarTab(); + } if (lock_scale_if_joint_position) { @@ -2377,7 +2709,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; @@ -2401,7 +2738,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) mLoading = false; if (mFMP) { - mFMP->getChild("confirm_checkbox")->set(FALSE); if (!mBaseModel.empty()) { const std::string& model_name = mBaseModel[0]->getName(); @@ -2410,6 +2746,10 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) { description_form->setText(model_name); } + // Add info to log that loading is complete (purpose: separator between loading and other logs) + LLSD args; + args["MODEL_NAME"] = model_name; // Teoretically shouldn't be empty, but might be better idea to add filename here + LLFloaterModelPreview::addStringToLog("ModelLoaded", args, false, loaded_lod); } } refresh(); @@ -2535,7 +2875,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; } @@ -3595,7 +3938,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; } @@ -3791,9 +4137,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 vertex_strider; @@ -3945,8 +4294,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) @@ -4035,11 +4397,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(); @@ -4050,6 +4414,7 @@ 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"]; @@ -4136,13 +4501,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 { @@ -4151,6 +4529,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; @@ -4174,11 +4553,19 @@ BOOL LLModelPreview::render() if (upload_skin && upload_joints) { mFMP->childEnable("lock_scale_if_joint_position"); + if (fmp) + { + fmp->updateAvatarTab(); + } } else { mFMP->childDisable("lock_scale_if_joint_position"); mFMP->childSetValue("lock_scale_if_joint_position", false); + if (fmp) + { + fmp->clearAvatarTab(); + } } //Only enable joint offsets if it passed the earlier critiquing @@ -4209,10 +4596,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(); @@ -4230,8 +4616,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 @@ -4343,8 +4730,8 @@ BOOL LLModelPreview::render() else { gGL.diffuseColor4fv(static_cast(base_col).mV); - } + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4fv(static_cast(edge_col).mV); @@ -4572,9 +4959,14 @@ BOOL LLModelPreview::render() 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 @@ -4587,6 +4979,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]; @@ -4604,16 +5041,14 @@ BOOL LLModelPreview::render() //quick 'n dirty software vertex skinning //build matrix palette - // use Mat4a part of the caching changes, no point in using the cache itself in the preview though. - //LLMatrix4 mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - const LLMeshSkinInfo *skin = &model->mSkinInfo; - U32 count = LLSkinningUtil::getMeshJointCount(skin); + // use Mat4a part of the caching changes, no point in using the cache itself in the preview though. //LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, // skin, getPreviewAvatar()); LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, getPreviewAvatar()); // + LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); U32 max_joints = LLSkinningUtil::getMaxJointCount(); @@ -4691,13 +5126,25 @@ BOOL LLModelPreview::render() gDebugProgram.bind(); } getPreviewAvatar()->renderCollisionVolumes(); - getPreviewAvatar()->renderBones(); + if (fmp->mTabContainer->getCurrentPanelIndex() == fmp->mAvatarTabIndex) + { + getPreviewAvatar()->renderBones(fmp->mSelectedJointName); + } + else + { + getPreviewAvatar()->renderBones(); + } if (shader) { shader->bind(); } } + if (pelvis_recalc) + { + // size/scale recalculation + getPreviewAvatar()->postPelvisSetRecalc(); + } } } @@ -4742,8 +5189,10 @@ void LLModelPreview::zoom(F32 zoom_amt) 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) @@ -4758,14 +5207,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]); - // Doesn't exist as of 16-06-2017 - //LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); - //combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - // - //LLComboBox* combo_box3 = mFMP->getChild("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"); @@ -4778,6 +5219,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->clearAvatarTab(); + } } refresh(); updateStatusMessages(); @@ -4795,8 +5243,11 @@ void LLFloaterModelPreview::onReset(void* user_data) { assert_main_thread(); + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); + fmp->clearLogTab(); + fmp->clearAvatarTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; @@ -4815,6 +5266,7 @@ void LLFloaterModelPreview::onUpload(void* user_data) assert_main_thread(); LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->clearLogTab(); mp->mUploadBtn->setEnabled(false); @@ -4915,6 +5367,11 @@ void LLFloaterModelPreview::setStatusMessage(const std::string& msg) mStatusMessage = msg; } +void LLFloaterModelPreview::toggleCalculateButton() +{ + toggleCalculateButton(true); +} + void LLFloaterModelPreview::modelUpdated(bool calculate_visible) { mModelPhysicsFee.clear(); @@ -5003,8 +5460,6 @@ void LLFloaterModelPreview::resetUploadOptions() childSetValue("lod_file_" + lod_name[lod], ""); } - getChild("physics_lod_combo")->setCurrentByIndex(0); - for(auto& p : mDefaultDecompParams) { std::string ctrl_name(p.first); @@ -5014,6 +5469,15 @@ void LLFloaterModelPreview::resetUploadOptions() ctrl->setValue(p.second); } } + getChild("physics_lod_combo")->setCurrentByIndex(0); + getChild("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) @@ -5056,7 +5520,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")) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 4a649c3cb2..a69a9f6812 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -57,7 +57,19 @@ class domController; class domSkin; class domMesh; class LLMenuButton; +class LLTabContainer; class LLToggleableMenu; +class LLViewerTextEditor; + + +class LLJointOverrideData +{ +public: + LLJointOverrideData() : mHasConflicts(false) {}; + std::map mPosOverrides; + bool mHasConflicts; +}; +typedef std::map joint_override_data_map_t; class LLFloaterModelPreview : public LLFloaterModelUploadBase { @@ -93,6 +105,11 @@ public: static void onMouseCaptureLostModelPreview(LLMouseHandler*); static void setUploadAmount(S32 amount) { sUploadAmount = amount; } + static void addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod = -1); + static void addStringToLog(const std::string& str, bool flash); + static void addStringToLog(const std::ostringstream& strm, bool flash); + void clearAvatarTab(); // clears table + void updateAvatarTab(); // populates table and data as nessesary void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void setPreviewLOD(S32 lod); @@ -115,6 +132,7 @@ public: void setViewOptionEnabled(const std::string& option, bool enabled); void enableViewOption(const std::string& option); void disableViewOption(const std::string& option); + void onShowSkinWeightChecked(LLUICtrl* ctrl); bool isModelLoading(); @@ -177,7 +195,8 @@ protected: // FIXME - this function and mStatusMessage have no visible effect, and the // actual status messages are managed by directly manipulation of // the UI element. - void setStatusMessage(const std::string& msg); + void setStatusMessage(const std::string& msg); + void addStringToLogTab(const std::string& str, bool flash); LLModelPreview* mModelPreview; @@ -206,24 +225,34 @@ protected: LLSD mModelPhysicsFee; private: - void onClickCalculateBtn(); + void onClickCalculateBtn(); + void onJointListSelection(); void onLoDSourceCommit(S32 lod); void modelUpdated(bool calculate_visible); // Toggles between "Calculate weights & fee" and "Upload" buttons. + void toggleCalculateButton(); void toggleCalculateButton(bool visible); // resets display options of model preview to their defaults. void resetDisplayOptions(); void resetUploadOptions(); + void clearLogTab(); void createSmoothComboBox(LLComboBox* combo_box, float min, float max); LLButton* mUploadBtn; LLButton* mCalculateBtn; + LLViewerTextEditor* mUploadLogText; + LLTabContainer* mTabContainer; + + S32 mAvatarTabIndex; // just to avoid any issues in case of xml changes + std::string mSelectedJointName; + + joint_override_data_map_t mJointOverrides[LLModel::NUM_LODS]; }; class LLMeshFilePicker : public LLFilePickerThread @@ -302,8 +331,9 @@ public: void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } //Accessors for the legacy rigs - const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } - void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; } + const bool isLegacyRigValid( void ) const { return mLegacyRigFlags == 0; } + U32 getLegacyRigFlags() const { return mLegacyRigFlags; } + void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; } static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); static bool lodQueryCallback(); @@ -418,7 +448,7 @@ private: float mPelvisZOffset; bool mRigValidJointUpload; - bool mLegacyRigValid; + U32 mLegacyRigFlags; bool mLastJointUpdate; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 18f818c9a3..4dcc08380f 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1700,13 +1700,16 @@ void LLVOAvatar::renderCollisionVolumes() } } -void LLVOAvatar::renderBones() +void LLVOAvatar::renderBones(const std::string &selected_joint) { LLGLEnable blend(GL_BLEND); avatar_joint_list_t::iterator iter = mSkeleton.begin(); - avatar_joint_list_t::iterator end = mSkeleton.end(); + avatar_joint_list_t::iterator end = mSkeleton.end(); + // For selected joints + static LLVector3 SELECTED_COLOR_OCCLUDED(1.0f, 1.0f, 0.0f); + static LLVector3 SELECTED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); // For bones with position overrides defined static LLVector3 OVERRIDE_COLOR_OCCLUDED(1.0f, 0.0f, 0.0f); static LLVector3 OVERRIDE_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); @@ -1733,7 +1736,18 @@ void LLVOAvatar::renderBones() LLVector3 pos; LLUUID mesh_id; - if (jointp->hasAttachmentPosOverride(pos,mesh_id)) + F32 sphere_scale = SPHERE_SCALEF; + + // We are in render, so it is preferable to implement selection + // in a different way, but since this is for debug/preview, this + // is low priority + if (jointp->getName() == selected_joint) + { + sphere_scale *= 16.f; + occ_color = SELECTED_COLOR_OCCLUDED; + visible_color = SELECTED_COLOR_VISIBLE; + } + else if (jointp->hasAttachmentPosOverride(pos,mesh_id)) { occ_color = OVERRIDE_COLOR_OCCLUDED; visible_color = OVERRIDE_COLOR_VISIBLE; @@ -1754,7 +1768,6 @@ void LLVOAvatar::renderBones() LLVector3 begin_pos(0,0,0); LLVector3 end_pos(jointp->getEnd()); - F32 sphere_scale = SPHERE_SCALEF; gGL.pushMatrix(); gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] ); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 842c6923e2..0c814dd699 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -467,7 +467,7 @@ public: F32 getLastSkinTime() { return mLastSkinTime; } U32 renderTransparent(BOOL first_pass); void renderCollisionVolumes(); - void renderBones(); + void renderBones(const std::string &selected_joint = std::string()); void renderJoints(); static void deleteCachedImages(bool clearAll=true); static void destroyGL(); diff --git a/indra/newview/skins/default/xui/de/floater_model_preview.xml b/indra/newview/skins/default/xui/de/floater_model_preview.xml index 4ffc7e76f8..9fea9201a7 100644 --- a/indra/newview/skins/default/xui/de/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/de/floater_model_preview.xml @@ -88,6 +88,16 @@ folgt + + Skinning wurde wegen zu vieler Gelenke deaktiviert: [JOINTS], Maximum: [MAX] + + + Geriggt an einem unbekannten Gelenk: [NAME] + + + Skinning wurde wegen [COUNT] unbekannter Gelenke deaktiviert. + + @@ -282,6 +292,19 @@ + + Skalierung (1=keine): + + + + Dimensionen: + + + [X] X [Y] X [Z] + + + + Skalierung (1=keine): @@ -296,9 +319,9 @@ Nur für Avatarmodelle: - - - + + + @@ -309,8 +332,29 @@ Z-Offset (Av. anheben / senken): - - + + Zu viele skingewichtete Gelenke + + + Modell hat unbekannte Gelenke + + + Gelenke: + + + [CONFLICTS] Konflikte in [JOINTS_COUNT] Gelenk(e) + + + Position übersteuert für Gelenk '[JOINT]': + + + + + + + + + Hinweis: Zu viele Objekte nutzen unnötigerweise den Standard-Anhängepunkt (Rechte Hand). @@ -318,6 +362,7 @@ Bitte ziehen Sie einen anderen Anhängepunkt nahe der Objektposition in Betracht +