diff options
Diffstat (limited to 'indra')
22 files changed, 1742 insertions, 445 deletions
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index a685df5925..dee642310e 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -408,7 +408,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; } @@ -511,7 +511,7 @@ void LLJoint::clearAttachmentPosOverrides() // getAllAttachmentPosOverrides() //-------------------------------------------------------------------- void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, - std::set<LLVector3>& distinct_pos_overrides) + std::set<LLVector3>& distinct_pos_overrides) const { num_pos_overrides = m_attachmentPosOverrides.count(); LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); @@ -525,7 +525,7 @@ void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, // getAllAttachmentScaleOverrides() //-------------------------------------------------------------------- void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides, - std::set<LLVector3>& distinct_scale_overrides) + std::set<LLVector3>& 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 aa997a4cf7..1b646b641f 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -53,6 +53,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: @@ -287,9 +289,9 @@ public: void showAttachmentScaleOverrides(const std::string& av_info) const; void getAllAttachmentPosOverrides(S32& num_pos_overrides, - std::set<LLVector3>& distinct_pos_overrides); + std::set<LLVector3>& distinct_pos_overrides) const; void getAllAttachmentScaleOverrides(S32& num_scale_overrides, - std::set<LLVector3>& distinct_scale_overrides); + std::set<LLVector3>& 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 4e468ff45f..5171621007 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -127,7 +127,7 @@ LLModelLoader::LLModelLoader( , mStateCallback(state_cb) , mOpaqueData(opaque_userdata) , mRigValidJointUpload(true) -, mLegacyRigValid(true) +, mLegacyRigFlags(0) , mNoNormalize(false) , mNoOptimize(false) , mCacheOnlyHitIfRigged(false) @@ -136,6 +136,7 @@ LLModelLoader::LLModelLoader( { assert_main_thread(); sActiveLoaderList.push_back(this) ; + mWarningsArray = LLSD::emptyArray(); } LLModelLoader::~LLModelLoader() @@ -146,6 +147,7 @@ LLModelLoader::~LLModelLoader() void LLModelLoader::run() { + mWarningsArray.clear(); doLoadModel(); doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); } @@ -387,7 +389,7 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st //2. It is suitable for upload as standard av with just skin weights bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); - bool isRigLegacyOK = isRigLegacy( jointListFromAsset ); + U32 legacy_rig_flags = determineRigLegacyFlags( jointListFromAsset ); // It's OK that both could end up being true. @@ -401,19 +403,16 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st setRigValidForJointPositionUpload( false ); } - if ( !isRigLegacyOK) - { - // This starts out true, becomes false if false for any loaded - // mesh. - setLegacyRigValid( false ); - } + legacy_rig_flags |= getLegacyRigFlags(); + // This starts as 0, changes if any loaded mesh has issues + setLegacyRigFlags(legacy_rig_flags); } //----------------------------------------------------------------------------- -// isRigLegacy() +// determineRigLegacyFlags() //----------------------------------------------------------------------------- -bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset ) +U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset ) { //No joints in asset if ( jointListFromAsset.size() == 0 ) @@ -426,7 +425,12 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &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 @@ -437,16 +441,24 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &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 643c45a6d8..fbc74554a0 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -42,6 +42,10 @@ typedef std::deque<std::string> 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<std::string> &jointListFromAsset ); //Determines if a rig is a legacy from the joint list - bool isRigLegacy( const std::vector<std::string> &jointListFromAsset ); + U32 determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset ); //Determines if a rig is suitable for upload bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &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: LLModelLoader::load_callback_t mLoadCallback; @@ -194,13 +202,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<LLModelLoader*> sActiveLoaderList; static bool isAlive(LLModelLoader* loader) ; }; diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 27444b7f5b..804204cce0 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -734,6 +734,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 7629ed1fea..572d36996c 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -205,6 +205,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 763c3aeb81..367c6c3c5b 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -132,6 +132,7 @@ LLScrollListCtrl::Params::Params() sort_ascending("sort_ascending", true), 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"), @@ -162,7 +163,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 43e1c0d707..8d00296183 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -97,6 +97,7 @@ public: // behavioral flags Optional<bool> 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 6521b883f8..750a3aff9c 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -220,6 +220,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"), font_halign("halign") @@ -259,6 +260,7 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mCustomIconCtrlUsed(p.use_custom_icon_ctrl), mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), mTabIconCtrlPad(p.tab_icon_ctrl_pad), + mEnableTabsFlashing(p.enable_tabs_flashing), mUseTabEllipses(p.use_ellipses) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -1102,6 +1104,9 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) p.pad_left( mLabelPadLeft ); p.pad_right(2); } + + // inits flash timer + p.button_flash_enable = mEnableTabsFlashing; // *TODO : It seems wrong not to use p in both cases considering the way p is initialized if (mCustomIconCtrlUsed) @@ -1637,6 +1642,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 6bf963313c..5339bec3dd 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -109,6 +109,11 @@ public: * Open tabs on hover in drag and drop situations */ Optional<bool> open_tabs_on_drag_and_drop; + + /** + * Enable tab flashing + */ + Optional<bool> enable_tabs_flashing; /** * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) @@ -198,6 +203,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); @@ -310,6 +316,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 83b851eed2..e6b3765370 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2228,6 +2228,18 @@ void LLTextBase::needsReflow(S32 index) mReflowIndex = llmin(mReflowIndex, index); } +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 8687e7aa2a..4e966b7cef 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -404,6 +404,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; } + S32 getMaxTextLength() { return mMaxTextByteLength; } // wide-char versions void setWText(const LLWString& text); @@ -432,6 +433,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/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0cb9ee3ace..c1a2c0ff7a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6661,8 +6661,190 @@ <key>Value</key> <integer>600</integer> </map> + <key>MeshPreviewCanvasColor</key> + <map> + <key>Comment</key> + <string>Canvas colour for the Mesh uploader</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.169</real> + <real>0.169</real> + <real>0.169</real> + <real>1.0</real> + </array> + </map> + <key>MeshPreviewEdgeColor</key> + <map> + <key>Comment</key> + <string>Edge colour for the Mesh uploader preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.4</real> + <real>0.4</real> + <real>0.4</real> + <real>1.0</real> + </array> + </map> + <key>MeshPreviewBaseColor</key> + <map> + <key>Comment</key> + <string>base diffuse colour for the Mesh uploader</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>1.0</real> + <real>1.0</real> + <real>1.0</real> + </array> + </map> + <key>MeshPreviewBrightnessColor</key> + <map> + <key>Comment</key> + <string>Brightness modifier</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color3</string> + <key>Value</key> + <array> + <real>0.9</real> + <real>0.9</real> + <real>0.9</real> + </array> + </map> + <key>MeshPreviewEdgeWidth</key> + <map> + <key>Comment</key> + <string>line thickness used when display edges is selected in mesh preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> + <key>MeshPreviewPhysicsEdgeColor</key> + <map> + <key>Comment</key> + <string>Edge colour for the Mesh uploader physics preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.0</real> + <real>0.25</real> + <real>0.5</real> + <real>0.25</real> + </array> + </map> + <key>MeshPreviewPhysicsFillColor</key> + <map> + <key>Comment</key> + <string>Fill colour for the Mesh uploader physics preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.0</real> + <real>0.5</real> + <real>1.0</real> + <real>0.5</real> + </array> + </map> + <key>MeshPreviewPhysicsEdgeWidth</key> + <map> + <key>Comment</key> + <string>line thickness used when display physics is selected in mesh preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0</real> + </map> + <key>MeshPreviewDegenerateEdgeColor</key> + <map> + <key>Comment</key> + <string>Edge colour for the Mesh uploader Degenerate preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.0</real> + <real>0.0</real> + <real>1.0</real> + </array> + </map> + <key>MeshPreviewDegenerateFillColor</key> + <map> + <key>Comment</key> + <string>Fill colour for the Mesh uploader Degenerate preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.0</real> + <real>0.0</real> + <real>0.5</real> + </array> + </map> + <key>MeshPreviewDegenerateEdgeWidth</key> + <map> + <key>Comment</key> + <string>line thickness used when display Degenerate is selected in mesh preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>3.0</real> + </map> + <key>MeshPreviewDegeneratePointSize</key> + <map> + <key>Comment</key> + <string>Large point size used to highlight degenerate triangle vertices in Mesh preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>8.0</real> + </map> + <key>MeshPreviewZoomLimit</key> + <map> + <key>Comment</key> + <string>Maximum Zoom level in preview</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>10.0</real> + </map> <key>MigrateCacheDirectory</key> - <map> + <map> <key>Comment</key> <string>Check for old version of disk cache to migrate to current location</string> <key>Persist</key> @@ -7912,7 +8094,17 @@ <key>Value</key> <integer>13</integer> </map> - + <key>PreviewRenderSize</key> + <map> + <key>Comment</key> + <string>Resolution of the image rendered for the mesh upload preview (must be a power of 2)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>1024</integer> + </map> <key>PreviewAmbientColor</key> <map> <key>Comment</key> @@ -7929,8 +8121,6 @@ <real>1.0</real> </array> </map> - - <key>PreviewDiffuse0</key> <map> <key>Comment</key> @@ -16517,3 +16707,4 @@ </map> </llsd> + diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl index 88959266c8..2cf17acf6b 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -93,6 +93,6 @@ void main() col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); col.rgb += light_diffuse[2].rgb*calcLocalLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); col.rgb += light_diffuse[3].rgb*calcLocalLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); - + col /= 2.0; vertex_color = col*color; } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 1e8c57ac6a..89c20904c1 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -125,11 +125,11 @@ BOOL LLViewerDynamicTexture::render() //----------------------------------------------------------------------------- void LLViewerDynamicTexture::preRender(BOOL clear_depth) { - //only images up to 1024*1024 are supported - llassert(mFullHeight <= 512); - llassert(mFullWidth <= 512); + gPipeline.allocatePhysicsBuffer(); + llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth())); + llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight())); - if (gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete()) + if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI) { //using offscreen render target, just use the bottom left corner mOrigin.set(0, 0); } @@ -216,7 +216,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() return TRUE; } - bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete(); + bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsATI; if (use_fbo) { diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index bc44e37c5a..99f5fa35cd 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" @@ -107,9 +109,7 @@ const double RETAIN_COEFFICIENT = 100; // So this const is used as a size of Smooth combobox list. const S32 SMOOTH_VALUES_NUMBER = 10; -// mCameraDistance -// Also see: mCameraZoom -const F32 MODEL_PREVIEW_CAMERA_DISTANCE = 16.f; +const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; void drawBoxOutline(const LLVector3& pos, const LLVector3& size); @@ -264,7 +264,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; @@ -307,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")); @@ -333,13 +336,20 @@ 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); + + childSetVisible("warning_title", false); + childSetVisible("warning_message", false); + initDecompControls(); LLView* preview_panel = getChild<LLView>("preview_panel"); @@ -395,6 +405,12 @@ BOOL LLFloaterModelPreview::postBuild() mUploadBtn = getChild<LLButton>("ok_btn"); mCalculateBtn = getChild<LLButton>("calculate_btn"); + mUploadLogText = getChild<LLViewerTextEditor>("log_text"); + mTabContainer = getChild<LLTabContainer>("import_tab"); + + LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + mAvatarTabIndex = mTabContainer->getIndexForPanel(panel); + panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); if (LLConvexDecomposition::getInstance() != NULL) { @@ -433,18 +449,58 @@ void LLFloaterModelPreview::initModelPreview() delete mModelPreview; } - mModelPreview = new LLModelPreview(512, 512, this ); - mModelPreview->setPreviewTarget(MODEL_PREVIEW_CAMERA_DISTANCE); + 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(); } } @@ -500,6 +556,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(); @@ -526,6 +584,82 @@ 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("avatar_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); + 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 @@ -626,6 +760,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(); @@ -669,6 +804,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() @@ -843,8 +1014,11 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) mModelPreview->zoom((F32)clicks * -0.2f); mModelPreview->refresh(); } - - return TRUE; + else + { + LLFloaterModelUploadBase::handleScrollWheel(x, y, clicks); + } + return TRUE; } /*virtual*/ @@ -1115,10 +1289,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*) ¶m[i]); } } @@ -1190,7 +1362,7 @@ void LLFloaterModelPreview::initDecompControls() //LL_INFOS() << "-----------------------------" << LL_ENDL; } } - + mDefaultDecompParams = mDecompParams; childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); } @@ -1220,6 +1392,231 @@ 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::clearAvatarTab() +{ + LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + joints_list->deleteAllItems(); + LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("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<LLTextBox>("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<LLTextBox>("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(); + 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("avatar_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + + if (joints_list->isEmpty()) + { + // Populate table + + std::map<std::string, std::string> 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<LLTextBox>("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; + } + + // Make sure we have space for new string + S32 editor_text_len = mUploadLogText->getLength(); + if (editor_max_len < (editor_text_len + add_text_len) + && mUploadLogText->getLineCount() <= 0) + { + mUploadLogText->getTextBoundingRect();// forces a reflow() to fix line count + } + while (editor_max_len < (editor_text_len + add_text_len)) + { + S32 shift = mUploadLogText->removeFirstLine(); + if (shift > 0) + { + // removed a line + editor_text_len -= shift; + } + else + { + //nothing to remove? + LL_WARNS() << "Failed to clear log lines" << LL_ENDL; + break; + } + } + + mUploadLogText->appendText(str, true); + + if (flash) + { + LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); + if (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 //----------------------------------------------------------------------------- @@ -1228,12 +1625,14 @@ 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 ) +, mImporterDebug(LLCachedControl<bool>(gSavedSettings, "ImporterDebug", false)) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -1443,7 +1842,6 @@ void LLModelPreview::rebuildUploadData() F32 max_scale = 0.f; - BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) @@ -1523,9 +1921,14 @@ void LLModelPreview::rebuildUploadData() if (!lod_model && i != LLModel::LOD_PHYSICS) { - if (importerDebug) - { - LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL; + if (mImporterDebug) + { + std::ostringstream out; + out << "Search of" << name_to_match; + out << " in LOD" << i; + out << " list failed. Searching for alternative among LOD lists."; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; @@ -1565,9 +1968,14 @@ void LLModelPreview::rebuildUploadData() // find reference instance for this model if (mBaseModel[idx] == base_model) { - if (importerDebug) + if (mImporterDebug) { - LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL; + std::ostringstream out; + out << "Attempting to use model index " << idx; + out << " for LOD" << i; + out << " of " << instance.mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } break; } @@ -1580,29 +1988,38 @@ void LLModelPreview::rebuildUploadData() // Assign that index from the model list for our LOD as the LOD model for this instance // lod_model = mModel[i][idx]; - if (importerDebug) - { - LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL; + if (mImporterDebug) + { + std::ostringstream out; + out << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } } - else if (importerDebug) + else if (mImporterDebug) { - LL_INFOS() << "List of models does not include index " << idx << LL_ENDL; + std::ostringstream out; + out << "List of models does not include index " << idx; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } } if (lod_model) { - if (importerDebug) - { + if (mImporterDebug) + { + std::ostringstream out; if (i == LLModel::LOD_PHYSICS) - { - LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL; + { + out << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel; } else - { - LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; - } + { + out << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel; + } + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } instance.mLOD[i] = lod_model; } @@ -1614,9 +2031,12 @@ void LLModelPreview::rebuildUploadData() // Note: we might need to assign it regardless of conditions like named search does, to prevent crashes. instance.mLOD[i] = instance.mLOD[i + 1]; } - if (importerDebug) + if (mImporterDebug) { - LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL; + std::ostringstream out; + out << "List of models does not include " << instance.mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } } } @@ -1648,8 +2068,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 ); } } @@ -1677,9 +2103,12 @@ void LLModelPreview::rebuildUploadData() } if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) { - if (importerDebug) - { - LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." << LL_ENDL; + if (mImporterDebug) + { + std::ostringstream out; + out << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models."; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } setLoadState( LLModelLoader::ERROR_MATERIALS ); mFMP->childDisable( "calculate_btn" ); @@ -1820,7 +2249,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; } @@ -2007,7 +2440,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() ; @@ -2017,7 +2450,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) @@ -2064,7 +2497,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) { @@ -2087,12 +2520,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) { @@ -2132,7 +2571,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } else { - BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); if (!legacyMatching) { @@ -2145,9 +2583,12 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) if (mBaseModel[idx]->mSubmodelID) { // don't do index-based renaming when the base model has submodels has_submodels = TRUE; - if (importerDebug) + if (mImporterDebug) { - LL_INFOS() << "High LOD has submodels" << LL_ENDL; + std::ostringstream out; + out << "High LOD has submodels"; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } break; } @@ -2171,9 +2612,12 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } } - if (importerDebug) + if (mImporterDebug) { - LL_INFOS() << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found" << LL_ENDL; + std::ostringstream out; + out << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found"; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } if (!name_based && !has_submodels) @@ -2195,9 +2639,14 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) case LLModel::LOD_HIGH: break; } - if (importerDebug) + if (mImporterDebug) { - 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; @@ -2221,7 +2670,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(); @@ -2230,6 +2678,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(); @@ -2355,7 +2807,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; } @@ -2723,8 +3178,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]; @@ -2778,20 +3245,34 @@ void LLModelPreview::updateStatusMessages() std::string instance_name = instance.mLabel; - BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); - if (importerDebug) + if (mImporterDebug) { // Useful for debugging generalized complaints below about total submeshes which don't have enough // context to address exactly what needs to be fixed to move towards compliance with the rules. // - LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts << LL_ENDL; - LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris << LL_ENDL; - LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes << LL_ENDL; - + std::ostringstream out; + out << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + + out.str(""); + out << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + + out.str(""); + out << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + + out.str(""); LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin(); while (mat_iter != lod_model->mMaterialList.end()) { - LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL; + out << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter); + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + out.str(""); mat_iter++; } } @@ -2814,43 +3295,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"); @@ -2975,14 +3470,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) @@ -3012,11 +3515,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()) @@ -3197,7 +3704,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; } @@ -3393,9 +3903,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; @@ -3543,8 +4056,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) @@ -3621,11 +4147,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(); @@ -3636,11 +4164,26 @@ 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(); @@ -3664,8 +4207,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); @@ -3706,13 +4248,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 { @@ -3721,6 +4276,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; @@ -3744,11 +4300,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 @@ -3779,7 +4343,7 @@ BOOL LLModelPreview::render() if (skin_weight) { - target_pos = getPreviewAvatar()->getPositionAgent(); + target_pos = getPreviewAvatar()->getPositionAgent() + offset; z_near = 0.01f; z_far = 1024.f; @@ -3799,8 +4363,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 @@ -3812,8 +4377,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; @@ -3898,16 +4462,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); @@ -3934,7 +4497,7 @@ BOOL LLModelPreview::render() //enable alpha blending on second pass but not first pass 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) @@ -3943,184 +4506,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; + bool render_mesh = true; + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); + LLModel::Decomposition& physics = model->mPhysics; - LLModel::Decomposition& physics = model->mPhysics; + if (!physics.mHull.empty()) + { + render_mesh = false; - 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(); - //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); - - 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); + gPipeline.enableLightsFullbright(); + //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); + + 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(); + + LLStrider<U16> idx; + buffer->getIndexStrider(idx, 0); - if (ll_is_degenerate(v1,v2,v3)) + 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 @@ -4133,6 +4713,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]; @@ -4150,10 +4775,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(); @@ -4193,11 +4817,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); @@ -4216,13 +4840,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(); + } } } @@ -4260,14 +4896,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) @@ -4282,12 +4921,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"); @@ -4300,6 +4933,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(); @@ -4317,12 +4957,16 @@ 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]; fmp->resetDisplayOptions(); + fmp->resetUploadOptions(); //reset model preview fmp->initModelPreview(); @@ -4336,6 +4980,7 @@ void LLFloaterModelPreview::onUpload(void* user_data) assert_main_thread(); LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->clearLogTab(); mp->mUploadBtn->setEnabled(false); @@ -4476,11 +5121,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); } } @@ -4507,6 +5156,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; @@ -4530,6 +5217,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()); @@ -4537,7 +5234,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 1c66570650..6f78d534f3 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<std::string, LLVector3> mPosOverrides; + bool mHasConflicts; +}; +typedef std::map<std::string, LLJointOverrideData> 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); @@ -109,11 +126,13 @@ public: void loadModel(S32 lod, const std::string& file_name, bool force_disable_slm = false); void onViewOptionChecked(LLUICtrl* ctrl); + void onUploadOptionChecked(LLUICtrl* ctrl); bool isViewOptionChecked(const LLSD& userdata); bool isViewOptionEnabled(const LLSD& userdata); 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(); @@ -154,6 +173,7 @@ protected: static void onAutoFillCommit(LLUICtrl*,void*); void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void draw3dPreview(); static void onExplodeCommit(LLUICtrl*, void*); @@ -175,11 +195,13 @@ 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; LLPhysicsDecomp::decomp_params mDecompParams; + LLPhysicsDecomp::decomp_params mDefaultDecompParams; S32 mLastMouseX; S32 mLastMouseY; @@ -203,23 +225,34 @@ protected: LLSD mModelPhysicsFee; private: - void onClickCalculateBtn(); - void toggleCalculateButton(); + 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 @@ -235,7 +268,9 @@ private: class LLModelPreview : public LLViewerDynamicTexture, public LLMutex -{ +{ + LOG_CLASS(LLModelPreview); + typedef boost::signals2::signal<void (F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost)> details_signal_t; typedef boost::signals2::signal<void (void)> model_loaded_signal_t; typedef boost::signals2::signal<void (bool)> model_updated_signal_t; @@ -298,8 +333,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(); @@ -314,6 +350,7 @@ public: static bool sIgnoreLoadedCallback; std::vector<S32> mLodsQuery; std::vector<S32> mLodsWithParsingError; + bool mHasDegenerate; protected: @@ -412,7 +449,7 @@ private: float mPelvisZOffset; bool mRigValidJointUpload; - bool mLegacyRigValid; + U32 mLegacyRigFlags; bool mLastJointUpdate; @@ -420,6 +457,7 @@ private: JointTransformMap mJointTransformMap; LLPointer<LLVOAvatar> mPreviewAvatar; + LLCachedControl<bool> mImporterDebug; }; #endif // LL_LLFLOATERMODELPREVIEW_H diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 7579eb1a90..69118afb6d 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1574,13 +1574,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); @@ -1607,7 +1610,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; + 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; @@ -1628,7 +1642,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 00dccc5d12..f19bdb3071 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -443,7 +443,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/pipeline.cpp b/indra/newview/pipeline.cpp index f0ed303f66..b36d0031af 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6600,7 +6600,7 @@ void LLPipeline::enableLightsPreview() light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse0); - light->setAmbient(LLColor4::black); + light->setAmbient(ambient); light->setSpecular(specular0); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); @@ -6611,7 +6611,7 @@ void LLPipeline::enableLightsPreview() light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse1); - light->setAmbient(LLColor4::black); + light->setAmbient(ambient); light->setSpecular(specular1); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); @@ -6621,7 +6621,7 @@ void LLPipeline::enableLightsPreview() light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse2); - light->setAmbient(LLColor4::black); + light->setAmbient(ambient); light->setSpecular(specular2); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 5a86eb06fb..e8c64dfef7 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -2,15 +2,16 @@ <floater can_close="true" can_drag_on_left="false" - can_minimize="false" - can_resize="false" - height="480" - min_height="480" + can_minimize="true" + can_resize="true" + height="625" + min_height="625" width="980" min_width="980" name="Model Preview" title="UPLOAD MODEL" - help_topic="upload_model" > + help_topic="upload_model" + legacy_header_height="25"> <string name="status_idle"></string> <string name="status_parse_error">Error: Dae parsing issue - see log for details.</string> @@ -33,19 +34,26 @@ <string name="mesh_status_missing_lod">Missing required level of detail.</string> <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string> <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string> + <string name="phys_status_degenerate_triangles">The physics mesh too dense remove the small thin triangles (see preview)</string> <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" --> <string name="decomposing">Analyzing...</string> <string name="simplifying">Simplifying...</string> <string name="tbd">TBD</string> + + <!-- Warnings and info from model loader--> + <string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string> + <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string> + <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string> + <string name="ModelLoaded">Model [MODEL_NAME] loaded</string> -<panel - follows="top|left" - height="455" - layout="topleft" - left="3" - name="left_panel" - top_pad="10" - width="630"> + <panel + follows="top|left" + height="595" + layout="topleft" + left="3" + name="left_panel" + top_pad="25" + width="635"> <panel follows="all" height="50" @@ -76,12 +84,13 @@ </panel> <tab_container follows="top|left" - top_pad="15" + top_pad="10" left="0" - height="300" + height="330" width="635" name="import_tab" - tab_position="top"> + tab_position="top" + enable_tabs_flashing="true"> <!-- LOD PANEL --> <panel help_topic="upload_model_lod" @@ -92,12 +101,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="lod_tab_border" top_pad="0" - width="629" /> + width="628" /> <text follows="left|top" height="18" @@ -688,7 +697,7 @@ left="10" name="lod_tab_border" top_pad="20" - width="605" /> + width="614" /> <check_box follows="top|left" height="15" @@ -730,12 +739,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="physics_tab_border" top_pad="0" - width="619"/> + width="628"/> <panel bg_alpha_color="0 0 0 0" bg_opaque_color="0 0 0 0.3" @@ -755,8 +764,9 @@ name="first_step_name" text_color="White" top_pad="0" - width="210"> - Step 1: Level of Detail + width="210" + valign="center"> + Step 1: Pick a physics model : </text> <combo_box follows="left|top" @@ -798,7 +808,7 @@ layout="topleft" left="18" name="physics_tab_border" - top_pad="15" + top_pad="10" width="589"/> <panel bg_alpha_color="0 0 0 0" @@ -807,7 +817,7 @@ follows="top|left" left="18" name="physics analysis" - top_pad="15" + top_pad="10" visible="true" width="589"> <text @@ -819,7 +829,7 @@ name="method_label" text_color="White" top_pad="0"> - Step 2: Analyze + Step 2: Convert to hulls (optional) </text> <text follows="top|left" @@ -905,7 +915,7 @@ layout="topleft" left="18" name="physics_tab_border" - top_pad="15" + top_pad="10" width="589"/> <panel bg_alpha_color="0 0 0 0" @@ -914,7 +924,7 @@ height="66" left="18" name="physics simplification" - top_pad="15" + top_pad="10" width="589"> <text text_color="White" @@ -1013,7 +1023,7 @@ layout="topleft" left="18" name="physics_tab_border" - top_pad="15" + top_pad="10" width="589"/> <panel bg_alpha_color="0 0 0 0" @@ -1075,10 +1085,9 @@ follows="left|top" height="19" layout="topleft" - left_pad="5" - top_delta="0" + top_pad="5" name="physics message" - width="270"> + width="589"> <icon follows="left|top" height="16" @@ -1093,7 +1102,7 @@ layout="topleft" left_pad="2" name="physics_status_message_text" - width="252" + width="573" top_delta="3"/> </panel> </panel> @@ -1105,12 +1114,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="border" top_pad="0" - width="619"/> + width="628"/> <text follows="top|left" height="16" @@ -1157,75 +1166,203 @@ label_text.text_color="White" left="20" top_pad="20"/> - <view_border - bevel_style="none" - follows="top|left" - height="0" - layout="topleft" - name="border" - top_pad="20" - width="579"/> - <text - follows="top|left" - height="15" - left="20" - name="include_label" - text_color="White" - top_pad="20" - width="150"> - For avatar models only: - </text> - <check_box - follows="top|left" - height="15" - label="Include skin weight" - label_text.text_color="White" - name="upload_skin" - top_pad="15"/> - <check_box - follows="top|left" - height="15" - label="Include joint positions" - label_text.text_color="White" - name="upload_joints" - top_pad="15"/> - <check_box - follows="top|left" - height="15" - label="Lock scale if joint position defined" - label_text.text_color="White" - name="lock_scale_if_joint_position" - top_pad="15"/> - <text - follows="top|left" - height="15" - layout="topleft" - left="220" - name="pelvis_offset_label" - text_color="White" - top="134" - width="200"> - Z offset (raise or lower avatar): - </text> - <spinner - follows="top|left" - height="20" - min_val="-3.00" - max_val="3.0" - name="pelvis_offset" - top_pad="10" - value="0.0" - width="80"/> </panel> + <panel + label="Overrides" + layout="topleft" + name="avatar_panel" + title="Avatar"> + <view_border + bevel_style="none" + follows="top|left" + height="306" + layout="topleft" + left="3" + name="avatar_tab_border" + top_pad="0" + width="628" /> + <check_box + follows="top|left" + height="15" + label="Include skin weight" + label_text.text_color="White" + name="upload_skin" + top="8" + left="20"/> + <check_box + follows="top|left" + height="15" + label="Include joint positions" + label_text.text_color="White" + name="upload_joints" + left_delta="0" + top_pad="7"/> + <check_box + follows="top|left" + height="15" + label="Lock scale if joint position defined" + label_text.text_color="White" + name="lock_scale_if_joint_position" + top_pad="7"/> + <text + follows="top|left" + height="15" + layout="topleft" + left="220" + name="pelvis_offset_label" + text_color="White" + top="8" + width="200"> + Z offset (raise or lower avatar): + </text> + <spinner + follows="top|left" + height="20" + min_val="-3.00" + max_val="3.0" + name="pelvis_offset" + top_pad="10" + value="0.0" + width="80"/> + <text + follows="top|left" + height="17" + left="425" + name="skin_too_many_joints" + text_color="Orange" + top="7" + width="195" + word_wrap="true"> + Too many skinned joints + </text> + <text + follows="top|left" + height="32" + left="425" + name="skin_unknown_joint" + text_color="Orange" + top="8" + width="195" + word_wrap="true"> + Model has an unknown joint(s) + </text> + <text + layout="topleft" + follows="top|left" + height="15" + left="20" + name="joints_descr" + top="73" + width="150"> + Joints: + </text> + <scroll_list + layout="topleft" + follows="top|left" + name="joints_list" + column_padding="0" + draw_heading="false" + draw_stripes="false" + commit_on_selection_change="true" + heading_height="23" + height="199" + left_delta="0" + top_pad="0" + width="200"/> + <text + layout="topleft" + follows="top|left" + height="15" + left_delta="0" + name="conflicts_description" + top_pad="2" + width="200"> + [CONFLICTS] conflicts in [JOINTS_COUNT] joints + </text> + <text + layout="topleft" + follows="top|left" + height="15" + left_pad="5" + name="pos_overrides_descr" + top="73" + width="300"> + Position overrides for joint '[JOINT]': + </text> + <scroll_list + layout="topleft" + follows="top|left" + name="pos_overrides_list" + column_padding="0" + draw_heading="true" + draw_stripes="false" + heading_height="23" + height="100" + left_delta="0" + top_pad="0" + width="385"> + <scroll_list.columns + label="Model" + name="model_name" + relative_width="0.49" /> + <scroll_list.columns + label="X" + name="axis_x" + relative_width="0.17" /> + <scroll_list.columns + label="Y" + name="axis_y" + relative_width="0.17" /> + <scroll_list.columns + label="Z" + name="axis_z" + relative_width="0.17" /> + </scroll_list> + </panel> + <panel + label="Log" + layout="topleft" + name="logs_panel" + title="Log"> + <view_border + bevel_style="none" + follows="top|left" + height="306" + layout="topleft" + left="3" + name="log_tab_border" + top_pad="0" + width="628" /> + <text_editor + type="string" + length="1" + embedded_items="false" + follows="top|left" + font="SansSerif" + ignore_tab="false" + layout="topleft" + height="306" + left="4" + top="0" + right="-1" + max_length="65536" + name="log_text" + parse_urls="true" + spellcheck="false" + read_only="true" + word_wrap="true"> + </text_editor> + </panel> </tab_container> <panel - follows="top|left" - height="80" - layout="top|left" - left="0" + follows="top|left|bottom" + layout="topleft" + height="195" + left="4" + border="true" name="weights_and_warning_panel" top_pad="3" - width="625"> + width="629"> <button follows="top|left" label="Calculate weights & fee" @@ -1265,10 +1402,10 @@ label_color="White" layout="topleft" name="reset_btn" - right="-2" + right="-5" top="3" height="20" - width="275"/> + width="265"/> <!-- ========== WEIGHTS ==========--> <text follows="top|left" @@ -1287,7 +1424,7 @@ left_pad="0" name="prim_weight" top_delta="0" - width="120" + width="130" word_wrap="true"> Land impact: [EQ] </text> @@ -1297,7 +1434,7 @@ left_pad="0" name="download_weight" top_delta="0" - width="100" + width="130" word_wrap="true"> Download: [ST] </text> @@ -1307,7 +1444,7 @@ layout="topleft" left_pad="0" name="physics_weight" - width="90" + width="130" word_wrap="true"> Physics: [PH] </text> @@ -1317,19 +1454,150 @@ layout="topleft" left_pad="0" name="server_weight" - width="83" + width="130" word_wrap="true"> Server: [SIM] </text> - <!-- ========== NOTE MESSAGE ========== --> + <!-- =========== Cost breakdown ======== --> + <panel + border="true" + top_pad="5" + layout="topleft" + left="6" + name="price_breakdown_panel" + width="120" + height="100"> + <text + layout="topleft" + left="3"> + Price Breakdown + </text> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="3" + name="price_breakdown_border" + top_pad="5" + width="110"/> + <text + height="80" + top_pad="5" + layout="topleft" + left="3" + name="price_breakdown_labels" + width="70" + word_wrap="false"> +Download: +Physics: +Instances: +Textures: +Model: + </text> + <text + height="80" + top_delta="0" + layout="topleft" + halign="right" + left_pad="0" + name="price_breakdown" + width="40" + word_wrap="false"> +[STREAMING] +[PHYSICS] +[INSTANCES] +[TEXTURES] +[MODEL] + </text> + </panel> + <!-- + Streaming breakdown numbers are available but not fully understood + uncommenting the following sections will display the numbers for debugging purposes + <text + height="80" + top_delta="0" + layout="topleft" + left="130" + name="streaming_breakdown_labels" + width="65" + word_wrap="true"> +Streaming/Download: +High: +Medium: +Low: +Lowest: + </text> <text + height="80" + top_delta="0" + layout="topleft" + left_pad="0" + name="streaming_breakdown" + width="95" + word_wrap="true"> +[STR_TOTAL] +[STR_HIGH] +[STR_MED] +[STR_LOW] +[STR_LOWEST] + </text>--> + <panel + border="true" + layout="topleft" + left_pad="265" + name="physics_costs_panel" + width="120" + height="100"> + <text + layout="topleft" + left="3"> + Physics Costs + </text> + <view_border + bevel_style="none" + follows="top|left" + height="0" + layout="topleft" + left="3" + name="price_breakdown_border" + top_pad="5" + width="110"/> + <text + height="80" + top_pad="5" + layout="topleft" + left="5" + name="physics_breakdown_labels" + width="65"> +Base Hull: +Mesh: +Analysed: + </text> + <text + height="80" + top_delta="0" + layout="topleft" + left_pad="0" + name="physics_breakdown" + width="40" + halign="right" + word_wrap="false" + visible="true"> +[PCH] +[PM] +[PHU] + </text>--> + </panel> + <!-- ========== NOTE MESSAGE ========== --> + <text font="SansSerif" layout="topleft" left="6" name="warning_title" - top_pad="10" + top_pad="5" text_color="DrYellow" - visible="false" + visible="true" width="40"> NOTE: </text> @@ -1340,44 +1608,51 @@ left_pad="1" name="warning_message" parse_urls="true" - top_delta="2" + top_delta="1" wrap="true" width="462" - visible="false"> + visible="true"> You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. + </text> + <text + text_color="Yellow" + layout="topleft" + top_pad="-2" + left="6" + name="status"> +[STATUS] </text> - <text text_color="Yellow" layout="topleft" top_delta="20" left="6" name="status">[STATUS]</text> - </panel> -</panel> - -<text - follows="left|top" - layout="topleft" - left="640" - name="lod_label" - text_color="White" - top="13" - height="15" - width="290"> - Preview: - </text> -<panel - border="true" - bevel_style="none" - follows="top|left" - name="preview_panel" - top_pad="4" - width="290" - height="290"/> - -<panel - follows="all" - height="130" - layout="topleft" - name="right_panel" - top_pad="5" - width="340"> + </panel> + + <text + follows="left|top" + layout="topleft" + left="640" + name="lod_label" + text_color="White" + top="29" + height="15" + width="290"> + Preview: + </text> + <panel + follows="all" + layout="topleft" + border="true" + bevel_style="none" + name="preview_panel" + top_pad="4" + width="325" + height="408"/> + <panel + follows="right|bottom" + can_resize="false" + height="140" + layout="topleft" + name="right_panel" + top_pad="5" + width="340"> <combo_box top_pad="3" follows="left|top" @@ -1386,10 +1661,10 @@ name="preview_lod_combo" width="150" tool_tip="LOD to view in preview render"> - <combo_item name="high"> High </combo_item> - <combo_item name="medium"> Medium </combo_item> - <combo_item name="low"> Low </combo_item> - <combo_item name="lowest"> Lowest </combo_item> + <combo_item name="high"> High </combo_item> + <combo_item name="medium"> Medium </combo_item> + <combo_item name="low"> Low </combo_item> + <combo_item name="lowest"> Lowest </combo_item> </combo_box> <text follows="top|left" @@ -1436,11 +1711,21 @@ </check_box> <check_box follows="top|left" + label="Joint position overrides" + label_text.text_color="White" + word_wrap="down" + width="130" + layout="topleft" + name="show_joint_overrides" + top_pad="8"> + </check_box> + <check_box + follows="top|left" label="Joints" label_text.text_color="White" layout="topleft" name="show_joint_positions" - top_pad="8"> + top_pad="17"> </check_box> <text follows="top|left" @@ -1460,5 +1745,5 @@ max_val="3.0" height="20" width="150"/> -</panel> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_script_debug.xml b/indra/newview/skins/default/xui/en/floater_script_debug.xml index cd88048d6b..6c49cfa1a8 100644 --- a/indra/newview/skins/default/xui/en/floater_script_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_script_debug.xml @@ -17,5 +17,6 @@ name="Preview Tabs" tab_position="bottom" top="16" - width="448" /> + width="448" + enable_tabs_flashing="true"/> </multi_floater> |