From 5b066ebb7a629c4126b175020712f84cc5800233 Mon Sep 17 00:00:00 2001 From: Mnikolenko ProductEngine <mnikolenko@productengine.com> Date: Wed, 19 Dec 2018 18:39:59 +0200 Subject: SL-10155 FIXED [MAC] Mesh upload tries to upload folder instead of opening it --- indra/newview/llfilepicker.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 0f22b6200f..b6fd70452e 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -101,6 +101,8 @@ LLFilePicker::LLFilePicker() mOFN.lpfnHook = NULL; mOFN.lpTemplateName = NULL; mFilesW[0] = '\0'; +#elif LL_DARWIN + mPickOptions = 0; #endif } -- cgit v1.2.3 From 3b932c27b7b1009ef404da5a7e0613d9cd3e7bf5 Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine <alihatskiy@productengine.com> Date: Thu, 3 Jan 2019 00:35:38 +0200 Subject: SL-10288 Mesh uploader changes from Firestorm --- doc/contributions.txt | 2 + indra/newview/app_settings/settings.xml | 199 +++++++- .../shaders/class1/objects/previewV.glsl | 8 +- indra/newview/lldynamictexture.cpp | 30 +- indra/newview/llfloatermodelpreview.cpp | 527 ++++++++++++++------- indra/newview/llfloatermodelpreview.h | 2 + indra/newview/pipeline.cpp | 6 +- .../skins/default/xui/en/floater_model_preview.xml | 369 ++++++++++----- 8 files changed, 844 insertions(+), 299 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index a09b6aff43..d2b1b6f134 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -256,6 +256,8 @@ Benja Kepler VWR-746 Benjamin Bigdipper Beth Walcher +Beq Janus + SL-10288 Bezilon Kasei Biancaluce Robbiani CT-225 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 3ad8b6cded..a58fa2d7a0 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6628,8 +6628,189 @@ <key>Value</key> <integer>600</integer> </map> - <key>MigrateCacheDirectory</key> - <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> + <map> <key>Comment</key> <string>Check for old version of disk cache to migrate to current location</string> <key>Persist</key> @@ -7868,7 +8049,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</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> @@ -7885,8 +8076,6 @@ <real>1.0</real> </array> </map> - - <key>PreviewDiffuse0</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl index 7f3f84398b..3424613e94 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -91,8 +91,10 @@ void main() // Collect normal lights (need to be divided by two, as we later multiply by 2) col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); - +// col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); + col.rgb += light_diffuse[2].rgb * calcDirectionalLight(norm, light_position[2].xyz); +// col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); + col.rgb += light_diffuse[3].rgb * calcDirectionalLight(norm, light_position[3].xyz); + col /= 2.0; vertex_color = col*color; } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index fa9a0712fa..af6977d3cd 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -125,11 +125,17 @@ BOOL LLViewerDynamicTexture::render() //----------------------------------------------------------------------------- void LLViewerDynamicTexture::preRender(BOOL clear_depth) { - //only images up to 512x512 are supported - llassert(mFullHeight <= 512); - llassert(mFullWidth <= 512); + // <FS:Beq> changes to support higher resolution rendering in the preview + ////only images up to 512x512 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.mWaterDis.isComplete() && !gGLManager.mIsATI) +// if (gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI) + if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI) +// </FS:Beq> { //using offscreen render target, just use the bottom left corner mOrigin.set(0, 0); } @@ -215,14 +221,15 @@ BOOL LLViewerDynamicTexture::updateAllInstances() { return TRUE; } - - bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI; - + // <FS:Beq> changes to support higher resolution rendering in the preview + // bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI; + bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI; if (use_fbo) { - gPipeline.mWaterDis.bindTarget(); +// gPipeline.mWaterDis.bindTarget(); + gPipeline.mPhysicsDisplay.bindTarget(); } - + // </FS:Beq> LLGLSLShader::bindNoShader(); LLVertexBuffer::unbind(); @@ -258,7 +265,10 @@ BOOL LLViewerDynamicTexture::updateAllInstances() if (use_fbo) { - gPipeline.mWaterDis.flush(); + // <FS:Beq> changes to support higher resolution rendering in the preview + // gPipeline.mWaterDis.flush(); + gPipeline.mPhysicsDisplay.flush(); + // </FS:Beq> } return ret; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 268c646719..78d97753d3 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -427,8 +427,11 @@ void LLFloaterModelPreview::initModelPreview() { delete mModelPreview; } - - mModelPreview = new LLModelPreview(512, 512, this ); + // <FS:Beq> mesh uploader changes to allow higher resolution render + // mModelPreview = new LLModelPreview(512, 512, this); + auto size = gSavedSettings.getS32("PreviewRenderSize"); + mModelPreview = new LLModelPreview(size, size, this ); + // </FS:Beq> mModelPreview->setPreviewTarget(16.f); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); @@ -438,8 +441,16 @@ void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) { if (mModelPreview) { - mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()]; - + // <FS:Beq> only show explode when phsyics is on + // 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(); } } @@ -653,6 +664,43 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) } } +// <FS:Beq> extracted method to simplify changes in layout +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() @@ -1218,6 +1266,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mResetJoints( false ) , mModelNoErrors( true ) , mLastJointUpdate( false ) +, mHasDegenerate( false ) // <FS:Beq> { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2710,8 +2759,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim void LLModelPreview::updateStatusMessages() { +// <FS:Beq> 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 + }; +// </FS:Beq> assert_main_thread(); + U32 has_physics_error{ PhysicsError::NONE }; // <FS:Beq> 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]; @@ -2800,44 +2861,72 @@ void LLModelPreview::updateStatusMessages() { mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; } - - bool has_degenerate = false; - + // <FS:Beq> make has_degenerate a member so that we can use it in the render method + // 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)// <FS:Beq> make has_degenerate a member { //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)// <FS:Beq> make has_degenerate a member { //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; )// <FS:Beq> make has_degenerate a member { - 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); - - if (ll_is_degenerate(v1,v2,v3)) + U16 index_a = face.mIndices[k + 0]; + U16 index_b = face.mIndices[k + 1]; + U16 index_c = face.mIndices[k + 2]; + // <FS:Beq> FIRE-23367/23387 - Allow forced empty triangle placeholders created by the LOD processing. + // 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;// <FS:Beq> make has_degenerate a member + // } + // else + // { + // k += 3; + // } + 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;// <FS:Beq> make has_degenerate a member + } } + k += 3; } } } } } + // <FS:Beq> 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); + } + // </FS:Beq> + mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); std::string mesh_status_na = mFMP->getString("mesh_status_na"); @@ -2962,14 +3051,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) @@ -2998,12 +3095,21 @@ void LLModelPreview::updateStatusMessages() mModelNoErrors = false; } } - - // 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) + // <FS:Beq> Improve the error checking the TO DO here is no longer applicable but not an FS comment so edited to stop it being picked up + //// To do 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 || mHasDegenerate) + //{ + // mFMP->childDisable("ok_btn"); + if (!mModelNoErrors || mHasDegenerate) { mFMP->childDisable("ok_btn"); + mFMP->childDisable("calculate_btn"); + } + else + { + mFMP->childEnable("ok_btn"); + mFMP->childEnable("calculate_btn"); } //add up physics triangles etc @@ -3619,11 +3725,30 @@ BOOL LLModelPreview::render() bool textures = mViewOption["show_textures"]; bool physics = mViewOption["show_physics"]; + // <FS:Beq> 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"); + // </FS:Beq> S32 width = getWidth(); S32 height = getHeight(); LLGLSUIDefault def; LLGLDisable no_blend(GL_BLEND); +// <FS:Beq> Clean up render of mesh preview +// LLGLEnable blend(GL_BLEND); +// gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); +// </FS:Beq> + LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_TRUE); LLGLDisable fog(GL_FOG); @@ -3642,9 +3767,9 @@ BOOL LLModelPreview::render() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); gGL.loadIdentity(); - - gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); - + // <FS:Beq> uploader improvements + //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); @@ -3792,8 +3917,11 @@ BOOL LLModelPreview::render() stop_glerror(); gGL.pushMatrix(); - const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + // <FS:Beq> mesh uploader improvements configurable brightness + //const F32 BRIGHTNESS = 0.9f; + //gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + gGL.color4fv(edge_col().mV); + // </FS:Beq> const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -3878,16 +4006,22 @@ BOOL LLModelPreview::render() } else { - gGL.diffuseColor4f(1,1,1,1); + // <FS:Beq> improved mesh uploader + // gGL.diffuseColor4f(1,1,1,1); + gGL.diffuseColor4fv(static_cast<LLColor4>(base_col).mV); + // </FS:Beq> + } 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); - + // <FS:Beq> improved mesh uploader + //gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); + gGL.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV); + // </FS:Beq> 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); @@ -3899,11 +4033,25 @@ BOOL LLModelPreview::render() if (physics) { + // <FS:Beq> model upload improvements - use the settings + ////Vector4a physicsFillColour(0.4, 0.4, 0.4, 0.4); + //const LLColor4 physicsFillColour(0.0, 0.5, 1.0, 0.5); + ////LLVector4a physicsEdgeColour(1.0, 1.0, 0.0, 1.0); + //const LLColor4 physicsEdgeColour=physicsFillColour*0.5; + //const LLColor4 degenerateFill(1.0, 0.0, 0.0, 0.5); + //const LLColor4 degenerateEdge(1.0,0.0,0.0,1.0); + // </FS:Beq> + glClear(GL_DEPTH_BUFFER_BIT); - - for (U32 i = 0; i < 2; i++) + //<FS:Beq> refactor to remove silly variable names + // for (U32 i = 0; i < 2; i++) + for (U32 pass = 0; pass < 2; pass++) + //</FS:Beq> { - if (i == 0) + //<FS:Beq> refactor to remove silly variable names + //if (i == 0) + if (pass == 0) + //</FS:Beq> { //depth only pass gGL.setColorMask(false, false); } @@ -3913,8 +4061,11 @@ BOOL LLModelPreview::render() } //enable alpha blending on second pass but not first pass - LLGLState blend(GL_BLEND, i); - + //<FS:Beq> refactor to remove silly variable names + //LLGLState blend(GL_BLEND, i); + LLGLState blend(GL_BLEND, pass); + //</FS:Beq> + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) @@ -3923,175 +4074,196 @@ 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); + + LLModel::Decomposition& physics = model->mPhysics; - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) + if (!physics.mHull.empty()) { - LLMutexLock(decomp->mMutex); - - LLModel::Decomposition& physics = model->mPhysics; + 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(LLColor4::white); - //show degenerate triangles - LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); - LLGLDisable cull(GL_CULL_FACE); - gGL.diffuseColor4f(1.f,0.f,0.f,1.f); - const LLVector4a scale(0.5f); + gGL.popMatrix(); + } - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + //<FS:Beq> refactor to remove silly variable names + // also only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] + //if (i > 0) + if (pass > 0 && mHasDegenerate) + //</FS:Beq> { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) + glLineWidth(deg_edge_width); + glPointSize(deg_point_size); +// <FS:Beq> This single line is why the degenerate triangles display has been crap forever. +// gPipeline.enableLightsFullbright(LLColor4::white); + //show degenerate triangles + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + LLGLDisable cull(GL_CULL_FACE); + const LLVector4a scale(0.5f); + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { - continue; - } + LLModelInstance& instance = *iter; - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - gGL.multMatrix((GLfloat*) mat.mMatrix); + if (!model) + { + continue; + } + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); + gGL.multMatrix((GLfloat*)mat.mMatrix); - LLModel::Decomposition& physics = model->mPhysics; - if (physics.mHull.empty()) + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - - for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + LLMutexLock(decomp->mMutex); - buffer->setBuffer(type_mask & buffer->getTypeMask()); + LLModel::Decomposition& physics = model->mPhysics; - LLStrider<LLVector3> pos_strider; - buffer->getVertexStrider(pos_strider, 0); - LLVector4a* pos = (LLVector4a*) pos_strider.get(); - - LLStrider<U16> idx; - buffer->getIndexStrider(idx, 0); + if (physics.mHull.empty()) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } - for (U32 i = 0; i < buffer->getNumIndices(); i += 3) + auto num_degenerate = 0; + //<FS:Beq> More nested i variable silliness + // for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) + 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]; + //</FS:Beq> + 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; + //<FS:Beq> rename inner most i to avoid merge confusion + 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); } } } @@ -4173,16 +4345,19 @@ BOOL LLModelPreview::render() } buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); + // <FS:Beq> configurable colour and width + //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); glLineWidth(1.f); } + // </FS:Beq> } } } @@ -4240,8 +4415,11 @@ 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); + // <FS:Beq> add configurable zoom TODO: stop clamping in render + // mCameraZoom = llclamp(new_zoom, 1.f, 10.f); + static LLCachedControl<F32> zoom_limit(gSavedSettings, "MeshPreviewZoomLimit"); + mCameraZoom = llclamp(new_zoom, 1.f, zoom_limit()); + // </FS:Beq> } void LLModelPreview::pan(F32 right, F32 up) @@ -4447,11 +4625,22 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) childSetTextArg("server_weight", "[SIM]", tbd); childSetTextArg("physics_weight", "[PH]", tbd); 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); + // <FS:Beq> add extended info fields + //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); + 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); + // </FS:Beq> } } @@ -4501,6 +4690,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())); +//<FS:Beq> Updates for enhanced Mesh feedback at upload + 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())); +//</FS:Beq> childSetVisible("upload_fee", true); childSetVisible("price_breakdown", true); mUploadBtn->setEnabled(isModelUploadAllowed()); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 7ec6a58ac7..564f4c39de 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -152,6 +152,7 @@ protected: static void onAutoFillCommit(LLUICtrl*,void*); void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void draw3dPreview(); static void onExplodeCommit(LLUICtrl*, void*); @@ -310,6 +311,7 @@ public: static bool sIgnoreLoadedCallback; std::vector<S32> mLodsQuery; std::vector<S32> mLodsWithParsingError; + bool mHasDegenerate; protected: diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 40d6d325ba..c7626304ed 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6582,7 +6582,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); @@ -6593,7 +6593,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); @@ -6603,7 +6603,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 3db431de1b..ec9104d5e7 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -2,12 +2,12 @@ <floater can_close="true" can_drag_on_left="false" - can_minimize="false" - can_resize="false" - height="480" - min_height="480" - width="980" - min_width="980" + can_minimize="true" + can_resize="true" + height="600" + min_height="600" + width="1024" + min_width="1024" name="Model Preview" title="UPLOAD MODEL" help_topic="upload_model" > @@ -33,19 +33,21 @@ <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="phys_status_no_havok">The Firestorm OpenSim build is not supported for physics upload in SL.</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> -<panel - follows="top|left" - height="455" - layout="topleft" - left="3" - name="left_panel" - top_pad="10" - width="630"> + <panel + follows="top|left" + height="580" + layout="topleft" + left="3" + name="left_panel" + top_pad="0" + width="630"> <panel follows="all" height="50" @@ -784,8 +786,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" @@ -827,7 +830,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" @@ -836,7 +839,7 @@ follows="top|left" left="18" name="physics analysis" - top_pad="15" + top_pad="10" visible="true" width="589"> <text @@ -848,7 +851,7 @@ name="method_label" text_color="White" top_pad="0"> - Step 2: Analyze + Step 2: Convert to hulls (optional) </text> <text follows="top|left" @@ -934,7 +937,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" @@ -943,7 +946,7 @@ height="66" left="18" name="physics simplification" - top_pad="15" + top_pad="10" width="589"> <text text_color="White" @@ -1042,7 +1045,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" @@ -1104,10 +1107,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" @@ -1122,7 +1124,7 @@ layout="topleft" left_pad="2" name="physics_status_message_text" - width="252" + width="573" top_delta="3"/> </panel> </panel> @@ -1248,13 +1250,14 @@ </panel> </tab_container> <panel - follows="top|left" - height="80" - layout="top|left" - left="0" + follows="top|left|bottom" + layout="topleft" + height="184" + left="4" + border="true" name="weights_and_warning_panel" top_pad="3" - width="625"> + width="629"> <button follows="top|left" label="Calculate weights & fee" @@ -1294,10 +1297,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" @@ -1316,7 +1319,7 @@ left_pad="0" name="prim_weight" top_delta="0" - width="120" + width="130" word_wrap="true"> Land impact: [EQ] </text> @@ -1326,7 +1329,7 @@ left_pad="0" name="download_weight" top_delta="0" - width="100" + width="130" word_wrap="true"> Download: [ST] </text> @@ -1336,7 +1339,7 @@ layout="topleft" left_pad="0" name="physics_weight" - width="90" + width="130" word_wrap="true"> Physics: [PH] </text> @@ -1346,17 +1349,148 @@ 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="price_breakdown_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" width="40"> @@ -1375,104 +1509,110 @@ visible="false"> You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. </text> - <text text_color="Yellow" layout="topleft" top_delta="20" left="6" name="status">[STATUS]</text> - + <text text_color="Yellow" layout="topleft" top_delta="5" 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"> - <combo_box - top_pad="3" + </panel> + <panel + follows="top|left|bottom|right" + can_resize="true" + name="right_panel" + top="0" + left="640" + background_visible="true" + width="375"> + <text follows="left|top" - height="18" layout="topleft" - name="preview_lod_combo" - width="150" - tool_tip="LOD to view in preview render"> + left="0" + name="lod_label" + text_color="White" + top="13" + height="15" + width="290"> + Preview: + </text> + <panel + can_resize="false" + follows="top|left" + height="20" + name="right_upper_panel" + top="8" + left="60" + background_visible="true" + width="315"> + <combo_box + top_pad="3" + can_resize="false" + follows="top|left" + height="18" + layout="topleft" + name="preview_lod_combo" + width="75" + 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_box> - <text - follows="top|left" - layout="topleft" - text_color="White" - top="5" - left_pad="20" - name="label_display" - width="50"> - Display... - </text> - <check_box - follows="top|left" - label="Edges" + </combo_box> + </panel> + </panel> + <panel + border="true" + bevel_style="none" + follows="top|left|right|bottom" + layout="topleft" + name="preview_panel" + top="30" + width="375" + height="525"/> + + <panel + follows="left|right|bottom" + layout="topleft" + height="40" + name="lower_right_panel" + top_pad="5" + width="375"> + <check_box + follows="right|bottom" + label="Edges" label_text.text_color="White" layout="topleft" - left_delta="0" name="show_edges" - top_pad="8"> - </check_box> + width="70" + left="0" + top_pad="8"/> <check_box - follows="top|left" + follows="right|bottom" + left_pad="8" label="Physics" label_text.text_color="White" - layout="topleft" - name="show_physics" - top_pad="8"> - </check_box> + name="show_physics"/> <check_box - follows="top|left" + follows="right|bottom" label="Textures" label_text.text_color="White" layout="topleft" name="show_textures" - top_pad="8"> - </check_box> + left_pad="0"/> <check_box - follows="top|left" - label="Skin weights" + follows="right|bottom" + label="Weights" label_text.text_color="White" layout="topleft" name="show_skin_weight" - top_pad="8"> - </check_box> + left_pad="0"/> <check_box - follows="top|left" + follows="right|bottom" label="Joints" label_text.text_color="White" layout="topleft" name="show_joint_positions" - top_pad="8"> - </check_box> + left_pad="0"/> <text - follows="top|left" + follows="right|bottom" layout="topleft" left="2" name="physics_explode_label" @@ -1482,12 +1622,13 @@ </text> <slider name="physics_explode" - follows="top|left" - top="100" - left="0" + follows="right|bottom" + valign="center" + top="15" + left="80" min_val="0.0" max_val="3.0" height="20" - width="150"/> -</panel> + width="120"/> + </panel> </floater> -- cgit v1.2.3 From c9d0222526c422ee7a5bff140b034e88aa5d0b39 Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine <alihatskiy@productengine.com> Date: Thu, 3 Jan 2019 01:19:41 +0200 Subject: SL-10288 settings.xml fix --- indra/newview/app_settings/settings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index a58fa2d7a0..091992d1ab 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6810,6 +6810,7 @@ <key>Value</key> <real>10.0</real> </map> + <key>MigrateCacheDirectory</key> <map> <key>Comment</key> <string>Check for old version of disk cache to migrate to current location</string> @@ -16469,3 +16470,4 @@ </map> </llsd> + -- cgit v1.2.3 From dd3a3693729cc700872a6e94e0ae4898cf25c3fb Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine <alihatskiy@productengine.com> Date: Thu, 3 Jan 2019 14:30:01 +0200 Subject: SL-10288 comments cleanup --- .../shaders/class1/objects/previewV.glsl | 2 - indra/newview/lldynamictexture.cpp | 15 +-- indra/newview/llfloatermodelpreview.cpp | 118 ++++----------------- 3 files changed, 21 insertions(+), 114 deletions(-) diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl index 3424613e94..de2ea2a065 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -91,9 +91,7 @@ void main() // Collect normal lights (need to be divided by two, as we later multiply by 2) col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); -// col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); col.rgb += light_diffuse[2].rgb * calcDirectionalLight(norm, light_position[2].xyz); -// col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); col.rgb += light_diffuse[3].rgb * calcDirectionalLight(norm, light_position[3].xyz); col /= 2.0; vertex_color = col*color; diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index af6977d3cd..e180d91461 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -125,17 +125,11 @@ BOOL LLViewerDynamicTexture::render() //----------------------------------------------------------------------------- void LLViewerDynamicTexture::preRender(BOOL clear_depth) { - // <FS:Beq> changes to support higher resolution rendering in the preview - ////only images up to 512x512 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.mWaterDis.isComplete() && !gGLManager.mIsATI) if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI) -// </FS:Beq> { //using offscreen render target, just use the bottom left corner mOrigin.set(0, 0); } @@ -221,15 +215,13 @@ BOOL LLViewerDynamicTexture::updateAllInstances() { return TRUE; } - // <FS:Beq> changes to support higher resolution rendering in the preview - // bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI; + bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI; if (use_fbo) { -// gPipeline.mWaterDis.bindTarget(); gPipeline.mPhysicsDisplay.bindTarget(); } - // </FS:Beq> + LLGLSLShader::bindNoShader(); LLVertexBuffer::unbind(); @@ -265,10 +257,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() if (use_fbo) { - // <FS:Beq> changes to support higher resolution rendering in the preview - // gPipeline.mWaterDis.flush(); gPipeline.mPhysicsDisplay.flush(); - // </FS:Beq> } return ret; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 78d97753d3..ffc993e868 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -427,11 +427,8 @@ void LLFloaterModelPreview::initModelPreview() { delete mModelPreview; } - // <FS:Beq> mesh uploader changes to allow higher resolution render - // mModelPreview = new LLModelPreview(512, 512, this); auto size = gSavedSettings.getS32("PreviewRenderSize"); mModelPreview = new LLModelPreview(size, size, this ); - // </FS:Beq> mModelPreview->setPreviewTarget(16.f); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); @@ -441,8 +438,6 @@ void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) { if (mModelPreview) { - // <FS:Beq> only show explode when phsyics is on - // mModelPreview->mViewOption[ctrl->getName()] = !mModelPreview->mViewOption[ctrl->getName()]; auto name = ctrl->getName(); mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; if (name == "show_physics") @@ -664,7 +659,6 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) } } -// <FS:Beq> extracted method to simplify changes in layout void LLFloaterModelPreview::draw3dPreview() { gGL.color3f(1.f, 1.f, 1.f); @@ -1266,7 +1260,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mResetJoints( false ) , mModelNoErrors( true ) , mLastJointUpdate( false ) -, mHasDegenerate( false ) // <FS:Beq> +, mHasDegenerate( false ) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -2759,7 +2753,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim void LLModelPreview::updateStatusMessages() { -// <FS:Beq> bit mask values for physics errors. used to prevent overwrite of single line status +// bit mask values for physics errors. used to prevent overwrite of single line status // TODO: use this to provied multiline status enum PhysicsError { @@ -2769,10 +2763,10 @@ void LLModelPreview::updateStatusMessages() TOOMANYHULLS=4, TOOMANYVERTSINHULL=8 }; -// </FS:Beq> + assert_main_thread(); - U32 has_physics_error{ PhysicsError::NONE }; // <FS:Beq> physics error bitmap + 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]; @@ -2861,38 +2855,25 @@ void LLModelPreview::updateStatusMessages() { mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; } - // <FS:Beq> make has_degenerate a member so that we can use it in the render method - // 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() && !mHasDegenerate; ++i)// <FS:Beq> make has_degenerate a member + 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 && !mHasDegenerate; ++j)// <FS:Beq> make has_degenerate a member + 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) && !mHasDegenerate; )// <FS:Beq> make has_degenerate a member + 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]; - // <FS:Beq> FIRE-23367/23387 - Allow forced empty triangle placeholders created by the LOD processing. - // 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;// <FS:Beq> make has_degenerate a member - // } - // else - // { - // k += 3; - // } + 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 { LL_DEBUGS("MeshValidation") << "Empty placeholder triangle (3 identical index 0 verts) ignored" << LL_ENDL; @@ -2904,7 +2885,7 @@ void LLModelPreview::updateStatusMessages() LLVector4a v3; v3.setMul(face.mPositions[index_c], scale); if (ll_is_degenerate(v1, v2, v3)) { - mHasDegenerate = true;// <FS:Beq> make has_degenerate a member + mHasDegenerate = true; } } k += 3; @@ -2914,7 +2895,7 @@ void LLModelPreview::updateStatusMessages() } } - // <FS:Beq> flag degenerates here rather than deferring to a MAV error later + // 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); @@ -2925,7 +2906,6 @@ void LLModelPreview::updateStatusMessages() LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Error"); degenerateIcon->setImage(img); } - // </FS:Beq> mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); @@ -3095,12 +3075,7 @@ void LLModelPreview::updateStatusMessages() mModelNoErrors = false; } } - // <FS:Beq> Improve the error checking the TO DO here is no longer applicable but not an FS comment so edited to stop it being picked up - //// To do 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 || mHasDegenerate) - //{ - // mFMP->childDisable("ok_btn"); + if (!mModelNoErrors || mHasDegenerate) { mFMP->childDisable("ok_btn"); @@ -3725,7 +3700,7 @@ BOOL LLModelPreview::render() bool textures = mViewOption["show_textures"]; bool physics = mViewOption["show_physics"]; - // <FS:Beq> Extra configurability, to be exposed later as controls? + // 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"); @@ -3738,16 +3713,12 @@ BOOL LLModelPreview::render() static LLCachedControl<LLColor4> deg_fill_col(gSavedSettings, "MeshPreviewDegenerateFillColor"); static LLCachedControl<F32> deg_edge_width(gSavedSettings, "MeshPreviewDegenerateEdgeWidth"); static LLCachedControl<F32> deg_point_size(gSavedSettings, "MeshPreviewDegeneratePointSize"); - // </FS:Beq> + S32 width = getWidth(); S32 height = getHeight(); LLGLSUIDefault def; LLGLDisable no_blend(GL_BLEND); -// <FS:Beq> Clean up render of mesh preview -// LLGLEnable blend(GL_BLEND); -// gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); -// </FS:Beq> LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_TRUE); @@ -3767,8 +3738,7 @@ BOOL LLModelPreview::render() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); gGL.loadIdentity(); - // <FS:Beq> uploader improvements - //gGL.color4f(0.169f, 0.169f, 0.169f, 1.f); + gGL.color4fv(static_cast<LLColor4>(canvas_col).mV); gl_rect_2d_simple( width, height ); @@ -3917,11 +3887,7 @@ BOOL LLModelPreview::render() stop_glerror(); gGL.pushMatrix(); - // <FS:Beq> mesh uploader improvements configurable brightness - //const F32 BRIGHTNESS = 0.9f; - //gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); gGL.color4fv(edge_col().mV); - // </FS:Beq> const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -4006,19 +3972,12 @@ BOOL LLModelPreview::render() } else { - // <FS:Beq> improved mesh uploader - // gGL.diffuseColor4f(1,1,1,1); gGL.diffuseColor4fv(static_cast<LLColor4>(base_col).mV); - // </FS:Beq> - } buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - // <FS:Beq> improved mesh uploader - //gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); gGL.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV); - // </FS:Beq> if (edges) { glLineWidth(edge_width); @@ -4033,25 +3992,10 @@ BOOL LLModelPreview::render() if (physics) { - // <FS:Beq> model upload improvements - use the settings - ////Vector4a physicsFillColour(0.4, 0.4, 0.4, 0.4); - //const LLColor4 physicsFillColour(0.0, 0.5, 1.0, 0.5); - ////LLVector4a physicsEdgeColour(1.0, 1.0, 0.0, 1.0); - //const LLColor4 physicsEdgeColour=physicsFillColour*0.5; - //const LLColor4 degenerateFill(1.0, 0.0, 0.0, 0.5); - //const LLColor4 degenerateEdge(1.0,0.0,0.0,1.0); - // </FS:Beq> - glClear(GL_DEPTH_BUFFER_BIT); - //<FS:Beq> refactor to remove silly variable names - // for (U32 i = 0; i < 2; i++) for (U32 pass = 0; pass < 2; pass++) - //</FS:Beq> { - //<FS:Beq> refactor to remove silly variable names - //if (i == 0) if (pass == 0) - //</FS:Beq> { //depth only pass gGL.setColorMask(false, false); } @@ -4061,10 +4005,7 @@ BOOL LLModelPreview::render() } //enable alpha blending on second pass but not first pass - //<FS:Beq> refactor to remove silly variable names - //LLGLState blend(GL_BLEND, i); LLGLState blend(GL_BLEND, pass); - //</FS:Beq> gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); @@ -4168,16 +4109,11 @@ BOOL LLModelPreview::render() gGL.popMatrix(); } - //<FS:Beq> refactor to remove silly variable names - // also only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] - //if (i > 0) + // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] if (pass > 0 && mHasDegenerate) - //</FS:Beq> { glLineWidth(deg_edge_width); glPointSize(deg_point_size); -// <FS:Beq> This single line is why the degenerate triangles display has been crap forever. -// gPipeline.enableLightsFullbright(LLColor4::white); //show degenerate triangles LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); LLGLDisable cull(GL_CULL_FACE); @@ -4215,13 +4151,10 @@ BOOL LLModelPreview::render() } auto num_degenerate = 0; - //<FS:Beq> More nested i variable silliness - // for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) auto num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); for (U32 v = 0; v < num_models; ++v) { LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; - //</FS:Beq> if(buffer->getNumVerts() < 3)continue; buffer->setBuffer(type_mask & buffer->getTypeMask()); @@ -4234,7 +4167,6 @@ BOOL LLModelPreview::render() buffer->getIndexStrider(idx, 0); LLVector4a v1, v2, v3; - //<FS:Beq> rename inner most i to avoid merge confusion for (U32 indices_offset = 0; indices_offset < buffer->getNumIndices(); indices_offset += 3) { v1.setMul(pos[*idx++], scale); @@ -4345,8 +4277,6 @@ BOOL LLModelPreview::render() } buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - // <FS:Beq> configurable colour and width - //gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); if (edges) { @@ -4357,7 +4287,6 @@ BOOL LLModelPreview::render() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLineWidth(1.f); } - // </FS:Beq> } } } @@ -4415,11 +4344,9 @@ void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) void LLModelPreview::zoom(F32 zoom_amt) { F32 new_zoom = mCameraZoom+zoom_amt; - // <FS:Beq> add configurable zoom TODO: stop clamping in render - // 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()); - // </FS:Beq> } void LLModelPreview::pan(F32 right, F32 up) @@ -4625,12 +4552,6 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) childSetTextArg("server_weight", "[SIM]", tbd); childSetTextArg("physics_weight", "[PH]", tbd); childSetTextArg("upload_fee", "[FEE]", tbd); - // <FS:Beq> add extended info fields - //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); std::string dashes = hasString("--") ? getString("--") : "--"; childSetTextArg("price_breakdown", "[STREAMING]", dashes); childSetTextArg("price_breakdown", "[PHYSICS]", dashes); @@ -4640,7 +4561,6 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) childSetTextArg("physics_breakdown", "[PCH]", dashes); childSetTextArg("physics_breakdown", "[PM]", dashes); childSetTextArg("physics_breakdown", "[PHU]", dashes); - // </FS:Beq> } } @@ -4690,7 +4610,7 @@ 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())); -//<FS:Beq> Updates for enhanced Mesh feedback at upload + 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())); @@ -4699,7 +4619,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() 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())); -//</FS:Beq> + childSetVisible("upload_fee", true); childSetVisible("price_breakdown", true); mUploadBtn->setEnabled(isModelUploadAllowed()); -- cgit v1.2.3 From e906af7c3c6e4efd84b344c9572167f6ddf836fc Mon Sep 17 00:00:00 2001 From: maxim_productengine <mnikolenko@productengine.com> Date: Fri, 11 Jan 2019 17:39:26 +0200 Subject: SL-10327 FIXED Scalable preview of mesh model is shown with black bar on top in the Upload Model menu --- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llfloatermodelpreview.cpp | 19 +++++++++++++++++-- .../skins/default/xui/en/floater_model_preview.xml | 8 +++----- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 091992d1ab..76cfc03b53 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8053,7 +8053,7 @@ <key>PreviewRenderSize</key> <map> <key>Comment</key> - <string>Resolution of the image rendered for the mesh upload preview</string> + <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> diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ffc993e868..62157306b1 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -427,8 +427,23 @@ void LLFloaterModelPreview::initModelPreview() { delete mModelPreview; } - auto size = gSavedSettings.getS32("PreviewRenderSize"); - mModelPreview = new LLModelPreview(size, size, this ); + + S32 tex_width = 512; + S32 tex_height = 512; + + S32 max_width = llmin(gSavedSettings.getS32("PreviewRenderSize"), (S32)gPipeline.mScreenWidth); + S32 max_height = llmin(gSavedSettings.getS32("PreviewRenderSize"), (S32)gPipeline.mScreenHeight); + + while ((tex_width << 1) <= max_width) + { + tex_width <<= 1; + } + while ((tex_height << 1) <= max_height) + { + tex_height <<= 1; + } + + mModelPreview = new LLModelPreview(tex_width, tex_height, this); mModelPreview->setPreviewTarget(16.f); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); 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 ec9104d5e7..1b038a0244 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1520,7 +1520,6 @@ Analysed: name="right_panel" top="0" left="640" - background_visible="true" width="375"> <text follows="left|top" @@ -1540,7 +1539,6 @@ Analysed: name="right_upper_panel" top="8" left="60" - background_visible="true" width="315"> <combo_box top_pad="3" @@ -1616,7 +1614,7 @@ Analysed: layout="topleft" left="2" name="physics_explode_label" - top="85" + bottom_pad="2" width="150"> Preview Spread: </text> @@ -1624,8 +1622,8 @@ Analysed: name="physics_explode" follows="right|bottom" valign="center" - top="15" - left="80" + left="105" + top_delta="-3" min_val="0.0" max_val="3.0" height="20" -- cgit v1.2.3 From a988b230c2d321dbc7270b2da83645cffb35c4dd Mon Sep 17 00:00:00 2001 From: maxim_productengine <mnikolenko@productengine.com> Date: Wed, 13 Feb 2019 16:55:22 +0200 Subject: SL-10328 FIXED Some parameters are not reset in the Upload Model menu when pressing button 'Clear settings & reset form' --- indra/newview/llfloatermodelpreview.cpp | 62 ++++++++++++++++++++++++++------- indra/newview/llfloatermodelpreview.h | 5 ++- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 62157306b1..10a8a1af3b 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -304,10 +304,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")); @@ -449,6 +449,16 @@ void LLFloaterModelPreview::initModelPreview() mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, _1)); } +void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) +{ + if (mModelPreview) + { + auto name = ctrl->getName(); + mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; + } + toggleCalculateButton(true); +} + void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) { if (mModelPreview) @@ -631,6 +641,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(); @@ -1156,10 +1167,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]); } } @@ -1231,7 +1240,7 @@ void LLFloaterModelPreview::initDecompControls() //LL_INFOS() << "-----------------------------" << LL_ENDL; } } - + mDefaultDecompParams = mDecompParams; childSetCommitCallback("physics_explode", LLFloaterModelPreview::onExplodeCommit, this); } @@ -4423,6 +4432,7 @@ void LLFloaterModelPreview::onReset(void* user_data) std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; fmp->resetDisplayOptions(); + fmp->resetUploadOptions(); //reset model preview fmp->initModelPreview(); @@ -4536,11 +4546,6 @@ void LLFloaterModelPreview::setStatusMessage(const std::string& msg) mStatusMessage = msg; } -void LLFloaterModelPreview::toggleCalculateButton() -{ - toggleCalculateButton(true); -} - void LLFloaterModelPreview::toggleCalculateButton(bool visible) { mCalculateBtn->setVisible(visible); @@ -4602,6 +4607,37 @@ 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], ""); + } + + getChild<LLComboBox>("physics_lod_combo")->setCurrentByIndex(0); + + for(auto& p : mDefaultDecompParams) + { + std::string ctrl_name(p.first); + LLUICtrl* ctrl = getChild<LLUICtrl>(ctrl_name); + if (ctrl) + { + ctrl->setValue(p.second); + } + } +} + void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) { mModelPhysicsFee = result; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 564f4c39de..41208daa64 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -109,6 +109,7 @@ 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); @@ -179,6 +180,7 @@ protected: LLModelPreview* mModelPreview; LLPhysicsDecomp::decomp_params mDecompParams; + LLPhysicsDecomp::decomp_params mDefaultDecompParams; S32 mLastMouseX; S32 mLastMouseY; @@ -203,7 +205,6 @@ protected: private: void onClickCalculateBtn(); - void toggleCalculateButton(); void onLoDSourceCommit(S32 lod); @@ -213,6 +214,8 @@ private: // resets display options of model preview to their defaults. void resetDisplayOptions(); + void resetUploadOptions(); + void createSmoothComboBox(LLComboBox* combo_box, float min, float max); LLButton* mUploadBtn; -- cgit v1.2.3 From 3cb20abfc928868fb6e95eaa78ea05b494d08af3 Mon Sep 17 00:00:00 2001 From: maxim_productengine <mnikolenko@productengine.com> Date: Thu, 10 Jan 2019 15:41:48 +0200 Subject: SL-10329 Increase panel height to avoid message overlapping --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 1b038a0244..ceea5b7421 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -34,7 +34,6 @@ <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="phys_status_no_havok">The Firestorm OpenSim build is not supported for physics upload in SL.</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> @@ -1252,7 +1251,7 @@ <panel follows="top|left|bottom" layout="topleft" - height="184" + height="197" left="4" border="true" name="weights_and_warning_panel" @@ -1441,7 +1440,7 @@ Lowest: border="true" layout="topleft" left_pad="265" - name="price_breakdown_panel" + name="physics_costs_panel" width="120" height="100"> <text @@ -1509,7 +1508,7 @@ Analysed: visible="false"> You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. </text> - <text text_color="Yellow" layout="topleft" top_delta="5" left="6" name="status"> + <text text_color="Yellow" layout="topleft" top_pad="-1" left="6" name="status"> [STATUS] </text> </panel> -- cgit v1.2.3 From 9bd1e26b0d7015c2da9f5e65e8ab8437c7e3bf57 Mon Sep 17 00:00:00 2001 From: maxim_productengine <mnikolenko@productengine.com> Date: Mon, 25 Feb 2019 16:28:31 +0200 Subject: SL-10613 Set default 'Smooth' parameter to None --- indra/newview/llfloatermodelpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 10a8a1af3b..5ce62d67d8 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4625,8 +4625,6 @@ void LLFloaterModelPreview::resetUploadOptions() childSetValue("lod_file_" + lod_name[lod], ""); } - getChild<LLComboBox>("physics_lod_combo")->setCurrentByIndex(0); - for(auto& p : mDefaultDecompParams) { std::string ctrl_name(p.first); @@ -4636,6 +4634,8 @@ void LLFloaterModelPreview::resetUploadOptions() ctrl->setValue(p.second); } } + getChild<LLComboBox>("physics_lod_combo")->setCurrentByIndex(0); + getChild<LLComboBox>("Cosine%")->setCurrentByIndex(0); } void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) -- cgit v1.2.3 From 4a0ebfad4234b59d5f9e6d9a8684b2126ad6292d Mon Sep 17 00:00:00 2001 From: maxim_productengine <mnikolenko@productengine.com> Date: Wed, 27 Feb 2019 17:17:44 +0200 Subject: SL-10611 FIXED Unable to pan the mesh model with 'ctrl + shift + mouse drag' in the preview window when 'Weights' is ticked --- indra/newview/llfloatermodelpreview.cpp | 27 ++++++++++++++++++++------- indra/newview/llfloatermodelpreview.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 5ce62d67d8..19e1d77b38 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -108,6 +108,8 @@ const double RETAIN_COEFFICIENT = 100; // So this const is used as a size of Smooth combobox list. const S32 SMOOTH_VALUES_NUMBER = 10; +const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; + void drawBoxOutline(const LLVector3& pos, const LLVector3& size); @@ -328,7 +330,7 @@ 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_positions")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onViewOptionChecked, this, _1)); childDisable("upload_skin"); @@ -459,6 +461,15 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) toggleCalculateButton(true); } +void LLFloaterModelPreview::onShowSkinWeightChecked(LLUICtrl* ctrl) +{ + if (mModelPreview) + { + mModelPreview->mCameraOffset.clearVec(); + onViewOptionChecked(ctrl); + } +} + void LLFloaterModelPreview::onViewOptionChecked(LLUICtrl* ctrl) { if (mModelPreview) @@ -3877,10 +3888,9 @@ BOOL LLModelPreview::render() if (skin_weight) { - target_pos = getPreviewAvatar()->getPositionAgent(); + target_pos = getPreviewAvatar()->getPositionAgent() + offset; z_near = 0.01f; z_far = 1024.f; - mCameraDistance = 16.f; //render avatar previews every frame refresh(); @@ -3898,8 +3908,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 @@ -4228,7 +4239,7 @@ BOOL LLModelPreview::render() target_pos = getPreviewAvatar()->getPositionAgent(); 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 @@ -4375,8 +4386,10 @@ void LLModelPreview::zoom(F32 zoom_amt) void LLModelPreview::pan(F32 right, F32 up) { - mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f); - mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f); + bool skin_weight = mViewOption["show_skin_weight"]; + F32 camera_distance = skin_weight ? SKIN_WEIGHT_CAMERA_DISTANCE : mCameraDistance; + mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * camera_distance / mCameraZoom, -1.f, 1.f); + mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * camera_distance / mCameraZoom, -1.f, 1.f); } void LLModelPreview::setPreviewLOD(S32 lod) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 41208daa64..096544cdbf 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -115,6 +115,7 @@ public: void setViewOptionEnabled(const std::string& option, bool enabled); void enableViewOption(const std::string& option); void disableViewOption(const std::string& option); + void onShowSkinWeightChecked(LLUICtrl* ctrl); bool isModelLoading(); -- cgit v1.2.3 From 5614f6cbf6867b0114a45aadbe1d975a3d71000c Mon Sep 17 00:00:00 2001 From: andreykproductengine <andreykproductengine@lindenlab.com> Date: Thu, 29 Nov 2018 21:04:35 +0200 Subject: SL-9747 [Mesh Uploader] Remove confusing model_metric from upload --- indra/llprimitive/llmodel.h | 3 --- indra/newview/llfloatermodelpreview.cpp | 3 --- indra/newview/llmeshrepository.cpp | 14 +---------- .../skins/default/xui/en/floater_model_preview.xml | 29 ---------------------- 4 files changed, 1 insertion(+), 48 deletions(-) diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index cf3288489a..51fa2f8079 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -154,7 +154,6 @@ public: void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); } std::string getName() const; - std::string getMetric() const {return mMetric;} EModelStatus getStatus() const {return mStatus;} static std::string getStatusString(U32 status) ; @@ -260,8 +259,6 @@ public: std::string mRequestedLabel; // name requested in UI, if any. std::string mLabel; // name computed from dae. - std::string mMetric; // user-supplied metric data for upload - LLVector3 mNormalizedScale; LLVector3 mNormalizedTranslation; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 19e1d77b38..8be405df9e 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1496,8 +1496,6 @@ void LLModelPreview::rebuildUploadData() std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString(); - std::string metric = mFMP->getChild<LLUICtrl>("model_category_combo")->getValue().asString(); - LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale"); F32 scale = scale_spinner->getValue().asReal(); @@ -1538,7 +1536,6 @@ void LLModelPreview::rebuildUploadData() if (base_model && !requested_name.empty()) { base_model->mRequestedLabel = requested_name; - base_model->mMetric = metric; } for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index e38bd8846d..a91817ba8a 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2174,7 +2174,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) std::map<LLModel*,S32> mesh_index; std::string model_name; - std::string model_metric; S32 instance_num = 0; @@ -2204,11 +2203,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) model_name = data.mBaseModel->getName(); } - if (model_metric.empty()) - { - model_metric = data.mBaseModel->getMetric(); - } - std::stringstream ostr; LLModel::Decomposition& decomp = @@ -2363,11 +2357,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) model_name = data.mBaseModel->getName(); } - if (model_metric.empty()) - { - model_metric = data.mBaseModel->getMetric(); - } - std::stringstream ostr; LLModel::Decomposition& decomp = @@ -2498,8 +2487,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) if (model_name.empty()) model_name = "mesh model"; result["name"] = model_name; - if (model_metric.empty()) model_metric = "MUT_Unspecified"; - res["metric"] = model_metric; + res["metric"] = "MUT_Unspecified"; result["asset_resources"] = res; dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num)); 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 ceea5b7421..274e6e6c7a 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -74,35 +74,6 @@ prevalidate_callback="ascii" top_pad="5" width="290" /> - <text - follows="left|top" - height="15" - layout="topleft" - left_pad="15" - name="model_category_label" - text_color="White" - top="0" - width="200"> - This model represents... - </text> - <combo_box - follows="left|top" - height="23" - left_pad="10" - name="model_category_combo" - top_pad="10" - width="200"> - <combo_box.drop_down_button - label_color="White"/> - <combo_item name="Choose one" label="Choose One..." value="MUT_Unspecified"/> - <combo_item name="Avatar shape" label="Avatar shape" value="MUT_AvatarShape"/> - <combo_item name="Avatar attachment" label="Avatar attachment" value="MUT_AvatarAttachment"/> - <combo_item name="Moving object (vehicle, animal)" label="Moving object (vehicle, animal)" value="MUT_MovingObject"/> - <combo_item name="Building Component" label="Building Component" value="MUT_BuildingComponent"/> - <combo_item name="Large, non moving etc" label="Large, non moving etc" value="MUT_LargeStationary"/> - <combo_item name="Smaller, non-moving etc" label="Smaller, non-moving etc" value="MUT_SmallStationary"/> - <combo_item name="Not really any of these" label="Not really any of these" value="MUT_Other"/> - </combo_box> </panel> <tab_container follows="top|left" -- cgit v1.2.3 From 580b35c8ea59187d5197e712022b706df3655f86 Mon Sep 17 00:00:00 2001 From: andreykproductengine <andreykproductengine@lindenlab.com> Date: Mon, 1 Apr 2019 20:22:25 +0300 Subject: SL-307 Display in-viewer all warning messages logged by the mesh uploader --- indra/llprimitive/llmodelloader.cpp | 4 + indra/llprimitive/llmodelloader.h | 5 + indra/llui/lltabcontainer.cpp | 4 + indra/llui/lltabcontainer.h | 6 + indra/llui/lltextbase.cpp | 12 ++ indra/llui/lltextbase.h | 2 + indra/newview/llfloatermodelpreview.cpp | 126 ++++++++++++++++++--- indra/newview/llfloatermodelpreview.h | 9 +- .../skins/default/xui/en/floater_model_preview.xml | 39 ++++++- 9 files changed, 191 insertions(+), 16 deletions(-) diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index 4e468ff45f..c8da68afc8 100644 --- a/indra/llprimitive/llmodelloader.cpp +++ b/indra/llprimitive/llmodelloader.cpp @@ -146,6 +146,7 @@ LLModelLoader::~LLModelLoader() void LLModelLoader::run() { + mWarningStream.clear(); doLoadModel(); doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); } @@ -426,6 +427,7 @@ 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; + mWarningStream << "Skinning disabled due to too many joints, maximum amount per mesh: " << mMaxJointsPerMesh << "\n"; return false; } @@ -437,12 +439,14 @@ 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; + mWarningStream << "Rigged to unrecognized joint name " << *it << "\n"; unknown_joint_count++; } } if (unknown_joint_count>0) { LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL; + mWarningStream << "Skinning disabled due to unknown joints\n"; return false; } diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h index 643c45a6d8..8dde176b54 100644 --- a/indra/llprimitive/llmodelloader.h +++ b/indra/llprimitive/llmodelloader.h @@ -185,6 +185,9 @@ public: return name != NULL && mJointMap.find(name) != mJointMap.end(); } + std::string logOut() { return mWarningStream.str(); } + void clearLog() { mWarningStream.clear(); } + protected: LLModelLoader::load_callback_t mLoadCallback; @@ -201,6 +204,8 @@ protected: JointTransformMap mJointTransformMap; + std::ostringstream mWarningStream; // preview floater will pull logs from here + static std::list<LLModelLoader*> sActiveLoaderList; static bool isAlive(LLModelLoader* loader) ; }; diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 1b2f09cff5..0af97bfab2 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -217,6 +217,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") @@ -1090,6 +1091,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) diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 4a5f08f5d3..a8cf380333 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; + + /** + * Open tabs on hover in drag and drop situations + */ + Optional<bool> enable_tabs_flashing; /** * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) @@ -308,6 +313,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 c570285856..f4713e19ba 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -2215,6 +2215,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 5fdde445ef..6913374bac 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -401,6 +401,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); @@ -429,6 +430,7 @@ public: S32 getLength() const { return getWText().length(); } S32 getLineCount() const { return mLineInfoList.size(); } + S32 removeFirstLine(); // returns removed length void addDocumentChild(LLView* view); void removeDocumentChild(LLView* view); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 8be405df9e..6387dfee55 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -76,6 +76,7 @@ #include "llsdserialize.h" #include "llsliderctrl.h" #include "llspinctrl.h" +#include "lltabcontainer.h" #include "lltoggleablemenu.h" #include "lltrans.h" #include "llvfile.h" @@ -83,6 +84,7 @@ #include "llcallbacklist.h" #include "llviewerobjectlist.h" #include "llanimationstates.h" +#include "llviewertexteditor.h" #include "llviewernetwork.h" #include "llviewershadermgr.h" @@ -263,7 +265,9 @@ void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LL LLFloaterModelPreview::LLFloaterModelPreview(const LLSD& key) : LLFloaterModelUploadBase(key), mUploadBtn(NULL), -mCalculateBtn(NULL) +mCalculateBtn(NULL), +mUploadLogText(NULL), +mTabContainer(NULL) { sInstance = this; mLastMouseX = 0; @@ -392,6 +396,13 @@ BOOL LLFloaterModelPreview::postBuild() mUploadBtn = getChild<LLButton>("ok_btn"); mCalculateBtn = getChild<LLButton>("calculate_btn"); + mUploadLogText = getChild<LLViewerTextEditor>("log_text"); + mTabContainer = getChild<LLTabContainer>("import_tab"); + + // Disable Logs tab untill it has something to show + LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, false); if (LLConvexDecomposition::getInstance() != NULL) { @@ -1280,6 +1291,64 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl gViewerWindow->showCursor(); } +//----------------------------------------------------------------------------- +// addStringToLog() +//----------------------------------------------------------------------------- +// 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); + } +} + +//----------------------------------------------------------------------------- +// addStringToLogTab() +//----------------------------------------------------------------------------- +void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash) +{ + if (str.empty()) + { + return; + } + + LLWString text = utf8str_to_wstring(str); + S32 add_text_len = text.length() + 1; // newline + S32 editor_max_len = mUploadLogText->getMaxTextLength(); + if (add_text_len > editor_max_len) + { + return; + } + + LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, true); + + // Make sure we have space for new string + S32 editor_text_len = mUploadLogText->getLength(); + while (editor_max_len < (editor_text_len + add_text_len)) + { + editor_text_len -= mUploadLogText->removeFirstLine(); + } + + mUploadLogText->appendText(str, true); + + if (flash && mTabContainer->getCurrentPanel() != panel) + { + mTabContainer->setTabPanelFlashing(panel, true); + } +} + //----------------------------------------------------------------------------- // LLModelPreview //----------------------------------------------------------------------------- @@ -1710,8 +1779,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 ); } } @@ -1882,7 +1957,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; } @@ -2259,7 +2338,12 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) if (importerDebug) { - LL_WARNS() << "Loded model name " << mModel[loaded_lod][idx]->mLabel << " for LOD " << loaded_lod << " doesn't match the base model. Renaming to " << name << LL_ENDL; + std::ostringstream out; + out << "Loded model name " << mModel[loaded_lod][idx]->mLabel; + out << " for LOD " << loaded_lod; + out << " doesn't match the base model. Renaming to " << name; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); } mModel[loaded_lod][idx]->mLabel = name; @@ -2417,7 +2501,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; } @@ -3288,7 +3375,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; } @@ -3484,9 +3574,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; @@ -3634,8 +3727,11 @@ void LLModelPreview::loadedCallback( LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) { - pPreview->loadModelCallback(lod); - } + LLFloaterModelPreview::addStringToLog(pPreview->mModelLoader->logOut(), true); + pPreview->mModelLoader->clearLog(); + pPreview->loadModelCallback(lod); // removes mModelLoader in some cases + } + } void LLModelPreview::stateChangedCallback(U32 state,void* opaque) @@ -4688,7 +4784,11 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) { - 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)); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 096544cdbf..c459b9296b 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -57,7 +57,9 @@ class domController; class domSkin; class domMesh; class LLMenuButton; +class LLTabContainer; class LLToggleableMenu; +class LLViewerTextEditor; class LLFloaterModelPreview : public LLFloaterModelUploadBase { @@ -93,6 +95,8 @@ public: static void onMouseCaptureLostModelPreview(LLMouseHandler*); static void setUploadAmount(S32 amount) { sUploadAmount = amount; } + static void addStringToLog(const std::string& str, bool flash); + static void addStringToLog(const std::ostringstream& strm, bool flash); void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void setPreviewLOD(S32 lod); @@ -176,7 +180,8 @@ protected: // FIXME - this function and mStatusMessage have no visible effect, and the // actual status messages are managed by directly manipulation of // the UI element. - void setStatusMessage(const std::string& msg); + void setStatusMessage(const std::string& msg); + void addStringToLogTab(const std::string& str, bool flash); LLModelPreview* mModelPreview; @@ -221,6 +226,8 @@ private: LLButton* mUploadBtn; LLButton* mCalculateBtn; + LLViewerTextEditor* mUploadLogText; + LLTabContainer* mTabContainer; }; class LLMeshFilePicker : public LLFilePickerThread 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 274e6e6c7a..cbc5aeb37d 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -82,7 +82,8 @@ height="300" width="635" name="import_tab" - tab_position="top"> + tab_position="top" + enable_tabs_flashing="true"> <!-- LOD PANEL --> <panel help_topic="upload_model_lod" @@ -98,7 +99,7 @@ left="3" name="lod_tab_border" top_pad="0" - width="629" /> + width="619" /> <text follows="left|top" height="18" @@ -1218,6 +1219,40 @@ value="0.0" width="80"/> </panel> + <panel + label="Log" + layout="topleft" + name="logs_panel" + title="Log"> + <view_border + bevel_style="none" + follows="top|left" + height="275" + layout="topleft" + left="3" + name="log_tab_border" + top_pad="0" + width="619" /> + <text_editor + type="string" + length="1" + embedded_items="false" + follows="top|left" + font="SansSerif" + ignore_tab="false" + layout="topleft" + height="275" + left="4" + top="0" + right="-11" + 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|bottom" -- cgit v1.2.3 From 6d9601a4d4153fc7e4a0c7bd934ccabafe293a44 Mon Sep 17 00:00:00 2001 From: andreykproductengine <andreykproductengine@lindenlab.com> Date: Tue, 28 May 2019 20:38:37 +0300 Subject: SL-1105 Pack a name for server to use --- indra/newview/llmeshrepository.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 38fd2d777e..31e3d408d7 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2277,6 +2277,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) instance_entry["material"] = LL_MCODE_WOOD; instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); instance_entry["mesh"] = mesh_index[data.mBaseModel]; + instance_entry["mesh_name"] = instance.mLabel; instance_entry["face_list"] = LLSD::emptyArray(); -- cgit v1.2.3 From 1840868178cbf3577ffa9757f093207f3bb10fd7 Mon Sep 17 00:00:00 2001 From: andreykproductengine <andreykproductengine@lindenlab.com> Date: Wed, 27 Nov 2019 20:34:26 +0200 Subject: SL-304 [Mesh Uploader] Localization support for logs, better warnings for joints --- indra/llprimitive/llmodelloader.cpp | 42 +++++++----- indra/llprimitive/llmodelloader.h | 19 ++++-- indra/newview/llfloatermodelpreview.cpp | 76 ++++++++++++++++++---- indra/newview/llfloatermodelpreview.h | 10 +-- .../skins/default/xui/en/floater_model_preview.xml | 31 ++++++++- 5 files changed, 136 insertions(+), 42 deletions(-) diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp index c8da68afc8..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,7 +147,7 @@ LLModelLoader::~LLModelLoader() void LLModelLoader::run() { - mWarningStream.clear(); + mWarningsArray.clear(); doLoadModel(); doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); } @@ -388,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. @@ -402,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 ) @@ -427,8 +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; - mWarningStream << "Skinning disabled due to too many joints, maximum amount per mesh: " << mMaxJointsPerMesh << "\n"; - 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 @@ -439,18 +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; - mWarningStream << "Rigged to unrecognized joint name " << *it << "\n"; + 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; - mWarningStream << "Skinning disabled due to unknown joints\n"; - 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 8dde176b54..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,8 +190,8 @@ public: return name != NULL && mJointMap.find(name) != mJointMap.end(); } - std::string logOut() { return mWarningStream.str(); } - void clearLog() { mWarningStream.clear(); } + const LLSD logOut() const { return mWarningsArray; } + void clearLog() { mWarningsArray.clear(); } protected: @@ -197,14 +202,14 @@ protected: void* mOpaqueData; bool mRigValidJointUpload; - bool mLegacyRigValid; + U32 mLegacyRigFlags; bool mNoNormalize; bool mNoOptimize; JointTransformMap mJointTransformMap; - std::ostringstream mWarningStream; // preview floater will pull logs from here + LLSD mWarningsArray; // preview floater will pull logs from here static std::list<LLModelLoader*> sActiveLoaderList; static bool isAlive(LLModelLoader* loader) ; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e1665dc255..b3012ed025 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -343,6 +343,9 @@ BOOL LLFloaterModelPreview::postBuild() childDisable("upload_joints"); childDisable("lock_scale_if_joint_position"); + childSetVisible("skin_too_many_joints", false); + childSetVisible("skin_unknown_joint", false); + initDecompControls(); LLView* preview_panel = getChild<LLView>("preview_panel"); @@ -1306,6 +1309,34 @@ 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) { @@ -1370,7 +1401,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mLodsQuery() , mLodsWithParsingError() , mPelvisZOffset( 0.0f ) -, mLegacyRigValid( false ) +, mLegacyRigFlags( U32_MAX ) , mRigValidJointUpload( false ) , mPhysicsSearchLOD( LLModel::LOD_PHYSICS ) , mResetJoints( false ) @@ -2160,7 +2191,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() ; @@ -3739,9 +3770,18 @@ void LLModelPreview::loadedCallback( LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) { - LLFloaterModelPreview::addStringToLog(pPreview->mModelLoader->logOut(), true); - pPreview->mModelLoader->clearLog(); - pPreview->loadModelCallback(lod); // removes mModelLoader in some cases + 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 } } @@ -3920,13 +3960,25 @@ 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_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 { diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index a080965ffc..5bb6714099 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -94,7 +94,8 @@ public: /*virtual*/ void onClose(bool app_quitting); static void onMouseCaptureLostModelPreview(LLMouseHandler*); - static void setUploadAmount(S32 amount) { sUploadAmount = amount; } + 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); @@ -308,8 +309,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(); @@ -423,7 +425,7 @@ private: float mPelvisZOffset; bool mRigValidJointUpload; - bool mLegacyRigValid; + U32 mLegacyRigFlags; bool mLastJointUpdate; 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 cbc5aeb37d..7e92e0360e 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -38,6 +38,12 @@ <string name="decomposing">Analyzing...</string> <string name="simplifying">Simplifying...</string> <string name="tbd">TBD</string> + + <!-- Warnings 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> + <panel follows="top|left" @@ -1184,20 +1190,41 @@ label_text.text_color="White" name="upload_skin" top_pad="15"/> + <text + follows="top|left" + height="17" + left="40" + name="skin_too_many_joints" + text_color="Orange" + top_pad="-2" + width="150"> + Too many skinned joints + </text> + <text + follows="top|left" + height="17" + left="40" + name="skin_unknown_joint" + text_color="Orange" + top_pad="-17" + width="150"> + Model has an unknown joint(s) + </text> <check_box follows="top|left" height="15" label="Include joint positions" label_text.text_color="White" name="upload_joints" - top_pad="15"/> + left_delta="-20" + top_pad="1"/> <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"/> + top_pad="16"/> <text follows="top|left" height="15" -- cgit v1.2.3 From 5c7b0dfe84f745bc5f6ccc0630ed1beb0ad87d00 Mon Sep 17 00:00:00 2001 From: andreykproductengine <andreykproductengine@lindenlab.com> Date: Thu, 28 Nov 2019 20:23:22 +0200 Subject: SL-304 [Mesh Uploader] A bit of cleanup (parse warnings, missing items, cleanup log) --- indra/newview/llfloatermodelpreview.cpp | 19 ++++++++++++------- indra/newview/llfloatermodelpreview.h | 1 + .../skins/default/xui/en/floater_model_preview.xml | 4 ---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b3012ed025..38b5fc271f 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -553,6 +553,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(); @@ -2410,7 +2412,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(); @@ -4561,12 +4562,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"); @@ -4596,8 +4591,10 @@ void LLFloaterModelPreview::onReset(void* user_data) { assert_main_thread(); + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); + fmp->clearLogTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; @@ -4616,6 +4613,7 @@ void LLFloaterModelPreview::onUpload(void* user_data) assert_main_thread(); LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->clearLogTab(); mp->mUploadBtn->setEnabled(false); @@ -4808,6 +4806,13 @@ void LLFloaterModelPreview::resetUploadOptions() 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; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 5bb6714099..8f6ca49cb8 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -224,6 +224,7 @@ private: void resetDisplayOptions(); void resetUploadOptions(); + void clearLogTab(); void createSmoothComboBox(LLComboBox* combo_box, float min, float max); 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 7e92e0360e..f5be4bab10 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1548,7 +1548,6 @@ Analysed: </panel> <panel follows="top|left|bottom|right" - can_resize="true" name="right_panel" top="0" left="640" @@ -1565,7 +1564,6 @@ Analysed: Preview: </text> <panel - can_resize="false" follows="top|left" height="20" name="right_upper_panel" @@ -1574,7 +1572,6 @@ Analysed: width="315"> <combo_box top_pad="3" - can_resize="false" follows="top|left" height="18" layout="topleft" @@ -1646,7 +1643,6 @@ Analysed: layout="topleft" left="2" name="physics_explode_label" - bottom_pad="2" width="150"> Preview Spread: </text> -- cgit v1.2.3 From c5859778bc18ef8114b57b616675de15a8e177cb Mon Sep 17 00:00:00 2001 From: andreykproductengine <andreykproductengine@lindenlab.com> Date: Fri, 17 Jan 2020 21:08:38 +0200 Subject: SL-379 WIP Joint overrides tab --- indra/llcharacter/lljoint.cpp | 4 +- indra/llcharacter/lljoint.h | 4 +- indra/llui/llscrolllistctrl.cpp | 3 +- indra/llui/llscrolllistctrl.h | 1 + indra/newview/CMakeLists.txt | 1 + indra/newview/llfloatermodelpreview.cpp | 141 ++++++++++++++++++++- indra/newview/llfloatermodelpreview.h | 8 +- indra/newview/lljointoverridedata.h | 52 ++++++++ indra/newview/llvoavatar.cpp | 50 ++++++++ indra/newview/llvoavatar.h | 26 ++-- .../skins/default/xui/en/floater_model_preview.xml | 116 +++++++++++++++++ 11 files changed, 383 insertions(+), 23 deletions(-) create mode 100644 indra/newview/lljointoverridedata.h diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index e2f512f86e..441ef1a352 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -510,7 +510,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(); @@ -524,7 +524,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 8112d246f2..6f69786f53 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -287,9 +287,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/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f4028057e8..a564b5b2ce 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"), @@ -161,7 +162,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 b35a8608e7..0d6ff67321 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/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 694e89ab99..7995e7ddf8 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1000,6 +1000,7 @@ set(viewer_HEADER_FILES llinventorymodelbackgroundfetch.h llinventoryobserver.h llinventorypanel.h + lljointoverridedata.h lljoystickbutton.h lllandmarkactions.h lllandmarklist.h diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 38b5fc271f..3e4d9020b7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -404,9 +404,15 @@ BOOL LLFloaterModelPreview::postBuild() mUploadLogText = getChild<LLViewerTextEditor>("log_text"); mTabContainer = getChild<LLTabContainer>("import_tab"); + // Disable Overrides tab untill it has something to show and set callbacks + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, false); + panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); + // Disable Logs tab untill it has something to show - LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); + panel = mTabContainer->getPanelByName("logs_panel"); + index = mTabContainer->getIndexForPanel(panel); mTabContainer->enableTabButton(index, false); if (LLConvexDecomposition::getInstance() != NULL) @@ -563,9 +569,12 @@ void LLFloaterModelPreview::onClickCalculateBtn() if (upload_joint_positions) { - // Diagnostic message showing list of joints for which joint offsets are defined. - // FIXME - given time, would be much better to put this in the UI, in updateStatusMessages(). - mModelPreview->getPreviewAvatar()->showAttachmentOverrides(); + // Todo: this probably should be enabled when checkbox enables, not on calculate + populateOverridesTab(); + } + else + { + disableOverridesTab(); } mUploadModelUrl.clear(); @@ -580,6 +589,89 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadBtn->setEnabled(false); } +void populate_list_with_vectors(LLScrollListCtrl *list, const std::set<LLVector3> &vector_set, const LLVector3 &active) +{ + if (vector_set.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::set<LLVector3>::const_iterator iter = vector_set.begin(); + std::set<LLVector3>::const_iterator end = vector_set.end(); + while (iter != end) + { + LLScrollListItem::Params item_params; + item_params.value = LLSD::Integer(count); + + cell_params.column = "override"; + if (*iter != active) + { + cell_params.value = ""; + } + else + { + cell_params.value = "active"; //todo: localize + } + + item_params.columns.add(cell_params); + + cell_params.column = "axis_x"; + cell_params.value = iter->mV[VX]; + item_params.columns.add(cell_params); + + cell_params.column = "axis_y"; + cell_params.value = iter->mV[VY]; + item_params.columns.add(cell_params); + + cell_params.column = "axis_z"; + cell_params.value = iter->mV[VZ]; + + item_params.columns.add(cell_params); + + list->addRow(item_params); + count++; + iter++; + } +} + +void LLFloaterModelPreview::onJointListSelection() +{ + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); + LLScrollListCtrl *joints_scale = panel->getChild<LLScrollListCtrl>("scale_overrides_list"); + LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("pos_overrides_descr"); + LLTextBox *joint_scale_descr = panel->getChild<LLTextBox>("scale_overrides_descr"); + + joints_pos->deleteAllItems(); + joints_scale->deleteAllItems(); + + LLScrollListItem *selected = joints_list->getFirstSelected(); + if (selected) + { + std::string label = selected->getValue().asString(); + LLJointOverrideData *data = &mJointOverrides[label]; + populate_list_with_vectors(joints_pos, data->mPosOverrides, data->mActivePosOverride); + populate_list_with_vectors(joints_scale, data->mScaleOverrides, data->mActiveScaleOverride); + + joint_pos_descr->setTextArg("[JOINT]", label); + joint_scale_descr->setTextArg("[JOINT]", label); + } + else + { + // temporary value (shouldn't happen) + std::string label = "mPelvis"; + joint_pos_descr->setTextArg("[JOINT]", label); + joint_scale_descr->setTextArg("[JOINT]", label); + } + +} + void LLFloaterModelPreview::onDescriptionKeystroke(LLUICtrl* ctrl) { // Workaround for SL-4186, server doesn't allow name changes after 'calculate' stage @@ -3861,7 +3953,7 @@ void LLModelPreview::addEmptyFace( LLModel* pTarget ) pTarget->setNumVolumeFaces( faceCnt+1 ); pTarget->setVolumeFaceData( faceCnt+1, pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices() ); -} +} //----------------------------------------------------------------------------- // render() @@ -4813,6 +4905,43 @@ void LLFloaterModelPreview::clearLogTab() mTabContainer->setTabPanelFlashing(panel, false); } +void LLFloaterModelPreview::populateOverridesTab() +{ + mJointOverrides.clear(); + attach_override_data_map_t attach_not_in_use; + mModelPreview->getPreviewAvatar()->getAttachmentOverrides(mJointOverrides, attach_not_in_use); + + if (mJointOverrides.empty()) + { + disableOverridesTab(); + return; + } + + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, true); + + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + joints_list->deleteAllItems(); + + joint_override_data_map_t::iterator joint_iter = mJointOverrides.begin(); + joint_override_data_map_t::iterator joint_end = mJointOverrides.end(); + while (joint_iter != joint_end) + { + const std::string& listName = joint_iter->first; + joints_list->addSimpleElement(listName); + joint_iter++; + } + joints_list->selectFirstItem(); +} + +void LLFloaterModelPreview::disableOverridesTab() +{ + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, false); +} + void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) { mModelPhysicsFee = result; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 8f6ca49cb8..8988dd2565 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -30,6 +30,7 @@ #include "llfloaternamedesc.h" #include "lldynamictexture.h" +#include "lljointoverridedata.h" #include "llquaternion.h" #include "llmeshrepository.h" #include "llmodel.h" @@ -213,7 +214,8 @@ protected: LLSD mModelPhysicsFee; private: - void onClickCalculateBtn(); + void onClickCalculateBtn(); + void onJointListSelection(); void onLoDSourceCommit(S32 lod); @@ -225,6 +227,8 @@ private: void resetUploadOptions(); void clearLogTab(); + void populateOverridesTab(); + void disableOverridesTab(); void createSmoothComboBox(LLComboBox* combo_box, float min, float max); @@ -232,6 +236,8 @@ private: LLButton* mCalculateBtn; LLViewerTextEditor* mUploadLogText; LLTabContainer* mTabContainer; + + joint_override_data_map_t mJointOverrides; }; class LLMeshFilePicker : public LLFilePickerThread diff --git a/indra/newview/lljointoverridedata.h b/indra/newview/lljointoverridedata.h new file mode 100644 index 0000000000..55e1878eec --- /dev/null +++ b/indra/newview/lljointoverridedata.h @@ -0,0 +1,52 @@ +/** + * @file lljointoverridedata.h + * @brief Declaration of LLJointOverrideData and LLAttachmentOverrideData + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_JOINTOVERRIDEDATA_H +#define LL_JOINTOVERRIDEDATA_H + +//#include <map> +//#include <string> +//#include <vector> + + +struct LLJointOverrideData +{ + std::set<LLVector3> mPosOverrides; + LLVector3 mActivePosOverride; + std::set<LLVector3> mScaleOverrides; + LLVector3 mActiveScaleOverride; +}; + +struct LLAttachmentOverrideData +{ + std::set<LLVector3> mPosOverrides; + LLVector3 mActivePosOverride; +}; + +typedef std::map<std::string, LLJointOverrideData> joint_override_data_map_t; +typedef std::map<std::string, LLAttachmentOverrideData> attach_override_data_map_t; + +#endif // LL_JOINTOVERRIDEDATA_H + diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index ca1216b89d..7700109fa4 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6374,6 +6374,56 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const } } +//----------------------------------------------------------------------------- +// getAttachmentOverrides +//----------------------------------------------------------------------------- +void LLVOAvatar::getAttachmentOverrides(joint_override_data_map_t &joint_overrides, attach_override_data_map_t &attach_overrides) const +{ + LLVector3 pos, scale; + LLUUID mesh_id; + S32 count = 0; + + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) + { + const LLJoint* pJoint = (*iter); + LLJointOverrideData data; + bool joint_override = false; + if (pJoint && pJoint->hasAttachmentPosOverride(pos, mesh_id)) + { + pJoint->getAllAttachmentPosOverrides(count, data.mPosOverrides); + data.mActivePosOverride = pos; + joint_override = true; + } + if (pJoint && pJoint->hasAttachmentScaleOverride(scale, mesh_id)) + { + pJoint->getAllAttachmentScaleOverrides(count, data.mPosOverrides); + data.mActiveScaleOverride = scale; + joint_override = true; + } + if (joint_override) + { + joint_overrides[pJoint->getName()] = data; + } + } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos, mesh_id)) + { + LLAttachmentOverrideData data; + attachment_pt->getAllAttachmentPosOverrides(count, data.mPosOverrides); + data.mActivePosOverride = pos; + attach_overrides[attachment_pt->getName()] = data; + } + } +} + //----------------------------------------------------------------------------- // removeAttachmentOverridesForObject //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 00dccc5d12..53a1d48d72 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -36,23 +36,25 @@ #include <boost/signals2/trackable.hpp> #include "llavatarappearance.h" +#include "llavatarappearancedefines.h" +#include "llavatarrendernotifier.h" +#include "llcontrol.h" +#include "llcharacter.h" #include "llchat.h" #include "lldrawpoolalpha.h" -#include "llviewerobject.h" -#include "llcharacter.h" -#include "llcontrol.h" -#include "llviewerjointmesh.h" -#include "llviewerjointattachment.h" -#include "llrendertarget.h" -#include "llavatarappearancedefines.h" -#include "lltexglobalcolor.h" #include "lldriverparam.h" -#include "llviewertexlayer.h" -#include "material_codes.h" // LL_MCODE_END +#include "lljointoverridedata.h" +#include "llrendertarget.h" #include "llrigginginfo.h" +#include "lltexglobalcolor.h" +#include "llviewerjointmesh.h" +#include "llviewerjointattachment.h" +#include "llviewerobject.h" #include "llviewerstats.h" +#include "llviewertexlayer.h" #include "llvovolume.h" -#include "llavatarrendernotifier.h" + +#include "material_codes.h" // LL_MCODE_END extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; @@ -215,6 +217,8 @@ public: void rebuildAttachmentOverrides(); void updateAttachmentOverrides(); void showAttachmentOverrides(bool verbose = false) const; + void getAttachmentOverrides(joint_override_data_map_t& joint_overrides, + attach_override_data_map_t& attach_overrides) const; void getAttachmentOverrideNames(std::set<std::string>& pos_names, std::set<std::string>& scale_names) const; 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 f5be4bab10..b675a3e3be 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1246,6 +1246,122 @@ value="0.0" width="80"/> </panel> + <panel + label="Overrides" + layout="topleft" + name="overrides_panel" + title="Overrides"> + <view_border + bevel_style="none" + follows="top|left" + height="275" + layout="topleft" + left="3" + name="log_tab_border" + top_pad="0" + width="619" /> + <text + layout="topleft" + follows="top|left" + height="15" + left="6" + name="joints_descr" + top="4" + width="300"> + 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="253" + left="6" + top_pad="0" + width="150"/> + <text + layout="topleft" + follows="top|left" + height="15" + left_pad="5" + name="pos_overrides_descr" + top="4" + 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="310"> + <scroll_list.columns + label="*" + name="override" + relative_width="0.22" /> + <scroll_list.columns + label="X" + name="axis_x" + relative_width="0.26" /> + <scroll_list.columns + label="Y" + name="axis_y" + relative_width="0.26" /> + <scroll_list.columns + label="Z" + name="axis_z" + relative_width="0.26" /> + </scroll_list> + <text + layout="topleft" + follows="top|left" + height="15" + left_delta="0" + name="scale_overrides_descr" + top_pad="3" + width="300"> + Scale overrides for joint '[JOINT]': + </text> + <scroll_list + layout="topleft" + follows="top|left" + name="scale_overrides_list" + column_padding="0" + draw_heading="true" + draw_stripes="false" + heading_height="23" + height="100" + left_delta="0" + top_pad="0" + width="310"> + <scroll_list.columns + label="*" + name="override" + relative_width="0.22" /> + <scroll_list.columns + label="X" + name="axis_x" + relative_width="0.26" /> + <scroll_list.columns + label="Y" + name="axis_y" + relative_width="0.26" /> + <scroll_list.columns + label="Z" + name="axis_z" + relative_width="0.26" /> + </scroll_list> + </panel> <panel label="Log" layout="topleft" -- cgit v1.2.3 From 748d25d1269751dc505a9ad93453d40b8dcea77f Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine <alihatskiy@productengine.com> Date: Tue, 21 Jan 2020 16:25:12 +0200 Subject: Copyright fix --- indra/newview/lljointoverridedata.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/lljointoverridedata.h b/indra/newview/lljointoverridedata.h index 55e1878eec..99baa5f334 100644 --- a/indra/newview/lljointoverridedata.h +++ b/indra/newview/lljointoverridedata.h @@ -3,7 +3,8 @@ * @brief Declaration of LLJointOverrideData and LLAttachmentOverrideData * * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer2020, Linden Research, Inc. + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public -- cgit v1.2.3 From 5fddc374566a0111375df2191b9c38cd8752881e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 5 Feb 2020 21:06:35 +0200 Subject: SL-12673 Make mesh uploader fit into 980px --- .../skins/default/xui/en/floater_model_preview.xml | 148 ++++++++++----------- 1 file changed, 74 insertions(+), 74 deletions(-) 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 b675a3e3be..bd8b764fde 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -6,8 +6,8 @@ can_resize="true" height="600" min_height="600" - width="1024" - min_width="1024" + width="980" + min_width="980" name="Model Preview" title="UPLOAD MODEL" help_topic="upload_model" > @@ -1656,121 +1656,121 @@ Analysed: width="462" visible="false"> You dont have rights to upload mesh models. [[VURL] Find out how] to get certified. - </text> + </text> <text text_color="Yellow" layout="topleft" top_pad="-1" left="6" name="status"> [STATUS] </text> </panel> </panel> + + <text + follows="left|top" + layout="topleft" + left="640" + name="lod_label" + text_color="White" + top="4" + height="15" + width="290"> + Preview: + </text> <panel - follows="top|left|bottom|right" + border="true" + bevel_style="none" + follows="top|left" + name="preview_panel" + top_pad="4" + width="325" + height="408"/> + <panel + follows="all" + can_resize="true" + height="140" + layout="topleft" name="right_panel" - top="0" - left="640" - width="375"> - <text + top_pad="5" + width="340"> + <combo_box + top_pad="3" follows="left|top" + height="18" + layout="topleft" + 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_box> + <text + follows="top|left" layout="topleft" - left="0" - name="lod_label" text_color="White" - top="13" - height="15" - width="290"> - Preview: + top="5" + left_pad="20" + name="label_display" + width="50"> + Display... </text> - <panel + <check_box follows="top|left" - height="20" - name="right_upper_panel" - top="8" - left="60" - width="315"> - <combo_box - top_pad="3" - follows="top|left" - height="18" - layout="topleft" - name="preview_lod_combo" - width="75" - 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_box> - </panel> - </panel> - <panel - border="true" - bevel_style="none" - follows="top|left|right|bottom" - layout="topleft" - name="preview_panel" - top="30" - width="375" - height="525"/> - - <panel - follows="left|right|bottom" - layout="topleft" - height="40" - name="lower_right_panel" - top_pad="5" - width="375"> - <check_box - follows="right|bottom" - label="Edges" + label="Edges" label_text.text_color="White" layout="topleft" + left_delta="0" name="show_edges" - width="70" - left="0" - top_pad="8"/> + top_pad="8"> + </check_box> <check_box - follows="right|bottom" - left_pad="8" + follows="top|left" label="Physics" label_text.text_color="White" - name="show_physics"/> + layout="topleft" + name="show_physics" + top_pad="8"> + </check_box> <check_box - follows="right|bottom" + follows="top|left" label="Textures" label_text.text_color="White" layout="topleft" name="show_textures" - left_pad="0"/> + top_pad="8"> + </check_box> <check_box - follows="right|bottom" - label="Weights" + follows="top|left" + label="Skin weights" label_text.text_color="White" layout="topleft" name="show_skin_weight" - left_pad="0"/> + top_pad="8"> + </check_box> <check_box - follows="right|bottom" + follows="top|left" label="Joints" label_text.text_color="White" layout="topleft" name="show_joint_positions" - left_pad="0"/> + top_pad="8"> + </check_box> <text - follows="right|bottom" + follows="top|left" layout="topleft" left="2" name="physics_explode_label" + top="85" width="150"> Preview Spread: </text> <slider name="physics_explode" - follows="right|bottom" - valign="center" - left="105" - top_delta="-3" + follows="top|left" + top="100" + left="0" min_val="0.0" max_val="3.0" height="20" - width="120"/> + width="150"/> </panel> </floater> -- cgit v1.2.3 From f851ce08d27c983423176e3508cebd9ac9f9cdd4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 6 Feb 2020 20:00:21 +0200 Subject: SL-548 Add control for joint positions in model upload preview --- indra/newview/llfloatermodelpreview.cpp | 56 ++++++++++++++++++++-- .../skins/default/xui/en/floater_model_preview.xml | 12 ++++- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2a8638e340..b846853755 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -337,6 +337,7 @@ BOOL LLFloaterModelPreview::postBuild() 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::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"); @@ -2295,7 +2296,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) @@ -2342,7 +2343,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) { @@ -2365,8 +2366,10 @@ 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); @@ -3977,6 +3980,7 @@ BOOL LLModelPreview::render() bool use_shaders = LLGLSLShader::sNoFixedFunction; bool edges = mViewOption["show_edges"]; + bool joints = mViewOption["show_joint_overrides"]; bool joint_positions = mViewOption["show_joint_positions"]; bool skin_weight = mViewOption["show_skin_weight"]; bool textures = mViewOption["show_textures"]; @@ -4068,6 +4072,7 @@ BOOL LLModelPreview::render() 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); @@ -4089,6 +4094,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; @@ -4496,6 +4502,7 @@ BOOL LLModelPreview::render() else { target_pos = getPreviewAvatar()->getPositionAgent(); + bool pelvis_recalc = false; LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera @@ -4532,6 +4539,41 @@ BOOL LLModelPreview::render() U32 count = LLSkinningUtil::getMeshJointCount(skin); LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, getPreviewAvatar()); + getPreviewAvatar()->clearAttachmentOverrides(); + if (joints) + { + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + for (U32 j = 0; j < count; ++j) + { + LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]); + if (joint && skin->mAlternateBindMatrix.size() > 0) + { + 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") + { + 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"); + } + } + } + } + } + LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); U32 max_joints = LLSkinningUtil::getMaxJointCount(); @@ -4601,6 +4643,11 @@ BOOL LLModelPreview::render() } } + if (pelvis_recalc) + { + // size/scale recalculation + getPreviewAvatar()->postPelvisSetRecalc(); + } } } @@ -4918,6 +4965,7 @@ void LLFloaterModelPreview::populateOverridesTab() { mJointOverrides.clear(); attach_override_data_map_t attach_not_in_use; + // Todo: use mAlternateBindMatrix mModelPreview->getPreviewAvatar()->getAttachmentOverrides(mJointOverrides, attach_not_in_use); if (mJointOverrides.empty()) 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 bd8b764fde..699ea7b9db 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1746,13 +1746,23 @@ Analysed: name="show_skin_weight" top_pad="8"> </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" -- cgit v1.2.3 From dd015ce7fc3f6ae3ccf0c6c7f04b2f1b94a90670 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 6 Feb 2020 20:33:09 +0200 Subject: SL-12673 Fixed resize --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 699ea7b9db..9009eeeb04 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1675,16 +1675,17 @@ Analysed: Preview: </text> <panel + follows="all" + layout="topleft" border="true" bevel_style="none" - follows="top|left" name="preview_panel" top_pad="4" width="325" height="408"/> <panel - follows="all" - can_resize="true" + follows="right|bottom" + can_resize="false" height="140" layout="topleft" name="right_panel" -- cgit v1.2.3 From 1a923ff8d3f4c1bc9c44be42b75295073e80a4c8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 7 Feb 2020 15:41:45 +0200 Subject: SL-548 Fixed pelvis position and optimized --- indra/newview/llfloatermodelpreview.cpp | 80 ++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b846853755..82b3fa200c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -3875,6 +3875,7 @@ void LLModelPreview::loadedCallback( LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) { + // 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(); @@ -3980,7 +3981,7 @@ BOOL LLModelPreview::render() bool use_shaders = LLGLSLShader::sNoFixedFunction; bool edges = mViewOption["show_edges"]; - bool joints = mViewOption["show_joint_overrides"]; + 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"]; @@ -4502,6 +4503,10 @@ BOOL LLModelPreview::render() else { target_pos = getPreviewAvatar()->getPositionAgent(); + getPreviewAvatar()->clearAttachmentOverrides(); // removes pelvis fixup + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + getPreviewAvatar()->addPelvisFixup(mPelvisZOffset, fake_mesh_id); bool pelvis_recalc = false; LLViewerCamera::getInstance()->setOriginAndLookAt( @@ -4518,6 +4523,43 @@ BOOL LLModelPreview::render() if (!model->mSkinWeights.empty()) { + const LLMeshSkinInfo *skin = &model->mSkinInfo; + U32 count = LLSkinningUtil::getMeshJointCount(skin); + + if (joint_overrides) + { + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + for (U32 j = 0; j < count; ++j) + { + LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]); + if (joint && skin->mAlternateBindMatrix.size() > 0) + { + 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") + { + 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]; @@ -4535,44 +4577,8 @@ 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()); - getPreviewAvatar()->clearAttachmentOverrides(); - if (joints) - { - LLUUID fake_mesh_id; - fake_mesh_id.generate(); - for (U32 j = 0; j < count; ++j) - { - LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]); - if (joint && skin->mAlternateBindMatrix.size() > 0) - { - 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") - { - 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"); - } - } - } - } - } LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); -- cgit v1.2.3 From f249365f23e5ed3509a7f665ead53d4e781ff6d2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 7 Feb 2020 16:59:50 +0200 Subject: SL-548 Fixed potential case where mJointNums will not be initialized --- indra/newview/llfloatermodelpreview.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 82b3fa200c..4e9e4754b3 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4524,16 +4524,24 @@ 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) + 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 && skin->mAlternateBindMatrix.size() > 0) + if (joint) { const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation(); if (joint->aboveJointPosThreshold(jointPos)) @@ -4544,7 +4552,7 @@ BOOL LLModelPreview::render() if (override_changed) { //If joint is a pelvis then handle old/new pelvis to foot values - if (joint->getName() == "mPelvis") + if (joint->getName() == "mPelvis")// or skin->mJointNames[j] { pelvis_recalc = true; } -- cgit v1.2.3 From 67b908cd2020231f30386294e4d0c5f199a007a0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 7 Feb 2020 18:43:31 +0200 Subject: SL-379 WIP Joint overrides tab --- indra/newview/CMakeLists.txt | 1 - indra/newview/llfloatermodelpreview.cpp | 191 +++++++++++++-------- indra/newview/llfloatermodelpreview.h | 24 ++- indra/newview/lljointoverridedata.h | 53 ------ indra/newview/llvoavatar.cpp | 50 ------ indra/newview/llvoavatar.h | 26 ++- .../skins/default/xui/en/floater_model_preview.xml | 53 +----- 7 files changed, 156 insertions(+), 242 deletions(-) delete mode 100644 indra/newview/lljointoverridedata.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index caa636cc83..cf8f99ed25 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -996,7 +996,6 @@ set(viewer_HEADER_FILES llinventorymodelbackgroundfetch.h llinventoryobserver.h llinventorypanel.h - lljointoverridedata.h lljoystickbutton.h lllandmarkactions.h lllandmarklist.h diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 4e9e4754b3..c791ca8e77 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -568,16 +568,6 @@ void LLFloaterModelPreview::onClickCalculateBtn() bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); bool lock_scale_if_joint_position = childGetValue("lock_scale_if_joint_position").asBoolean(); - if (upload_joint_positions) - { - // Todo: this probably should be enabled when checkbox enables, not on calculate - populateOverridesTab(); - } - else - { - disableOverridesTab(); - } - mUploadModelUrl.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, @@ -590,9 +580,9 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadBtn->setEnabled(false); } -void populate_list_with_vectors(LLScrollListCtrl *list, const std::set<LLVector3> &vector_set, const LLVector3 &active) +void populate_list_with_map(LLScrollListCtrl *list, const std::map<std::string, LLVector3> &vector_map) { - if (vector_set.empty()) + if (vector_map.empty()) { return; } @@ -602,35 +592,28 @@ void populate_list_with_vectors(LLScrollListCtrl *list, const std::set<LLVector3 // Start out right justifying numeric displays cell_params.font_halign = LLFontGL::HCENTER; - std::set<LLVector3>::const_iterator iter = vector_set.begin(); - std::set<LLVector3>::const_iterator end = vector_set.end(); + 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 = "override"; - if (*iter != active) - { - cell_params.value = ""; - } - else - { - cell_params.value = "active"; //todo: localize - } + 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->mV[VX]; + cell_params.value = iter->second.mV[VX]; item_params.columns.add(cell_params); cell_params.column = "axis_y"; - cell_params.value = iter->mV[VY]; + cell_params.value = iter->second.mV[VY]; item_params.columns.add(cell_params); cell_params.column = "axis_z"; - cell_params.value = iter->mV[VZ]; + cell_params.value = iter->second.mV[VZ]; item_params.columns.add(cell_params); @@ -642,12 +625,12 @@ void populate_list_with_vectors(LLScrollListCtrl *list, const std::set<LLVector3 void LLFloaterModelPreview::onJointListSelection() { + S32 display_lod = mModelPreview->mPreviewLOD; LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); LLScrollListCtrl *joints_scale = panel->getChild<LLScrollListCtrl>("scale_overrides_list"); LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("pos_overrides_descr"); - LLTextBox *joint_scale_descr = panel->getChild<LLTextBox>("scale_overrides_descr"); joints_pos->deleteAllItems(); joints_scale->deleteAllItems(); @@ -656,19 +639,19 @@ void LLFloaterModelPreview::onJointListSelection() if (selected) { std::string label = selected->getValue().asString(); - LLJointOverrideData *data = &mJointOverrides[label]; - populate_list_with_vectors(joints_pos, data->mPosOverrides, data->mActivePosOverride); - populate_list_with_vectors(joints_scale, data->mScaleOverrides, data->mActiveScaleOverride); + LLJointOverrideData &data = mJointOverrides[display_lod][label]; + populate_list_with_map(joints_pos, data.mPosOverrides); + //populate_list_with_vectors(joints_scale, data.mScaleOverrides, data.mActiveScaleOverride); joint_pos_descr->setTextArg("[JOINT]", label); - joint_scale_descr->setTextArg("[JOINT]", label); + //joint_scale_descr->setTextArg("[JOINT]", label); } else { // temporary value (shouldn't happen) std::string label = "mPelvis"; joint_pos_descr->setTextArg("[JOINT]", label); - joint_scale_descr->setTextArg("[JOINT]", label); + //joint_scale_descr->setTextArg("[JOINT]", label); } } @@ -1450,6 +1433,98 @@ void LLFloaterModelPreview::addStringToLog(const std::ostringstream& strm, bool } } + +void LLFloaterModelPreview::clearOverridesTab() +{ + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + joints_list->deleteAllItems(); + + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mJointOverrides[i].clear(); + } +} + +void LLFloaterModelPreview::showOverridesTab() +{ + S32 display_lod = mModelPreview->mPreviewLOD; + if (mModelPreview->mModel[display_lod].empty()) + { + return; + } + + // Todo: Are overrides identical for all lods? + if (mJointOverrides[display_lod].empty()) + { + // populate list + 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).inRange(-F_APPROXIMATELY_ZERO, F_APPROXIMATELY_ZERO)) + { + // File contains multiple meshes with conflicting joint offsets + // preview may be incorrect, upload result might wary (depends onto mesh_id). + data.mHasConflicts = true; + } + data.mPosOverrides[model->getName()] = jointPos; + + } + } + } + } + } + + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, true); + + LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); + + joint_override_data_map_t::iterator joint_iter = mJointOverrides[display_lod].begin(); + joint_override_data_map_t::iterator joint_end = mJointOverrides[display_lod].end(); + while (joint_iter != joint_end) + { + const std::string& listName = joint_iter->first; + + LLScrollListItem::Params item_params; + item_params.value(listName); + + LLScrollListCell::Params cell_params; + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.value = listName; + if (joint_iter->second.mHasConflicts) + { + cell_params.color = LLColor4::orange; + } + + item_params.columns.add(cell_params); + + joints_list->addRow(item_params, ADD_BOTTOM); + joint_iter++; + } + joints_list->selectFirstItem(); +} + +void LLFloaterModelPreview::hideOverridesTab() +{ + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + S32 index = mTabContainer->getIndexForPanel(panel); + mTabContainer->enableTabButton(index, false); +} + //----------------------------------------------------------------------------- // addStringToLogTab() //----------------------------------------------------------------------------- @@ -2374,6 +2449,11 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) mViewOption["show_joint_positions"] = true; fmp->childSetValue("upload_joints", true); } + else + { + fmp->clearOverridesTab(); + fmp->hideOverridesTab(); + } if (lock_scale_if_joint_position) { @@ -4119,11 +4199,19 @@ BOOL LLModelPreview::render() if (upload_skin && upload_joints) { mFMP->childEnable("lock_scale_if_joint_position"); + if (fmp) + { + fmp->showOverridesTab(); + } } else { mFMP->childDisable("lock_scale_if_joint_position"); mFMP->childSetValue("lock_scale_if_joint_position", false); + if (fmp) + { + fmp->hideOverridesTab(); + } } //Only enable joint offsets if it passed the earlier critiquing @@ -4757,6 +4845,7 @@ void LLFloaterModelPreview::onReset(void* user_data) LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); fmp->clearLogTab(); + fmp->clearOverridesTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; @@ -4975,44 +5064,6 @@ void LLFloaterModelPreview::clearLogTab() mTabContainer->setTabPanelFlashing(panel, false); } -void LLFloaterModelPreview::populateOverridesTab() -{ - mJointOverrides.clear(); - attach_override_data_map_t attach_not_in_use; - // Todo: use mAlternateBindMatrix - mModelPreview->getPreviewAvatar()->getAttachmentOverrides(mJointOverrides, attach_not_in_use); - - if (mJointOverrides.empty()) - { - disableOverridesTab(); - return; - } - - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, true); - - LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); - joints_list->deleteAllItems(); - - joint_override_data_map_t::iterator joint_iter = mJointOverrides.begin(); - joint_override_data_map_t::iterator joint_end = mJointOverrides.end(); - while (joint_iter != joint_end) - { - const std::string& listName = joint_iter->first; - joints_list->addSimpleElement(listName); - joint_iter++; - } - joints_list->selectFirstItem(); -} - -void LLFloaterModelPreview::disableOverridesTab() -{ - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, false); -} - void LLFloaterModelPreview::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) { mModelPhysicsFee = result; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 8988dd2565..f53478f31b 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -30,7 +30,6 @@ #include "llfloaternamedesc.h" #include "lldynamictexture.h" -#include "lljointoverridedata.h" #include "llquaternion.h" #include "llmeshrepository.h" #include "llmodel.h" @@ -62,6 +61,16 @@ 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 { public: @@ -95,10 +104,13 @@ public: /*virtual*/ void onClose(bool app_quitting); 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 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); + static void addStringToLog(const std::ostringstream& strm, bool flash); + void clearOverridesTab(); + void showOverridesTab(); + void hideOverridesTab(); void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void setPreviewLOD(S32 lod); @@ -227,8 +239,6 @@ private: void resetUploadOptions(); void clearLogTab(); - void populateOverridesTab(); - void disableOverridesTab(); void createSmoothComboBox(LLComboBox* combo_box, float min, float max); @@ -237,7 +247,7 @@ private: LLViewerTextEditor* mUploadLogText; LLTabContainer* mTabContainer; - joint_override_data_map_t mJointOverrides; + joint_override_data_map_t mJointOverrides[LLModel::NUM_LODS]; }; class LLMeshFilePicker : public LLFilePickerThread diff --git a/indra/newview/lljointoverridedata.h b/indra/newview/lljointoverridedata.h deleted file mode 100644 index 99baa5f334..0000000000 --- a/indra/newview/lljointoverridedata.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file lljointoverridedata.h - * @brief Declaration of LLJointOverrideData and LLAttachmentOverrideData - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_JOINTOVERRIDEDATA_H -#define LL_JOINTOVERRIDEDATA_H - -//#include <map> -//#include <string> -//#include <vector> - - -struct LLJointOverrideData -{ - std::set<LLVector3> mPosOverrides; - LLVector3 mActivePosOverride; - std::set<LLVector3> mScaleOverrides; - LLVector3 mActiveScaleOverride; -}; - -struct LLAttachmentOverrideData -{ - std::set<LLVector3> mPosOverrides; - LLVector3 mActivePosOverride; -}; - -typedef std::map<std::string, LLJointOverrideData> joint_override_data_map_t; -typedef std::map<std::string, LLAttachmentOverrideData> attach_override_data_map_t; - -#endif // LL_JOINTOVERRIDEDATA_H - diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index dac516d15c..3b51d07f96 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6375,56 +6375,6 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const } } -//----------------------------------------------------------------------------- -// getAttachmentOverrides -//----------------------------------------------------------------------------- -void LLVOAvatar::getAttachmentOverrides(joint_override_data_map_t &joint_overrides, attach_override_data_map_t &attach_overrides) const -{ - LLVector3 pos, scale; - LLUUID mesh_id; - S32 count = 0; - - // Bones - for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); - iter != mSkeleton.end(); ++iter) - { - const LLJoint* pJoint = (*iter); - LLJointOverrideData data; - bool joint_override = false; - if (pJoint && pJoint->hasAttachmentPosOverride(pos, mesh_id)) - { - pJoint->getAllAttachmentPosOverrides(count, data.mPosOverrides); - data.mActivePosOverride = pos; - joint_override = true; - } - if (pJoint && pJoint->hasAttachmentScaleOverride(scale, mesh_id)) - { - pJoint->getAllAttachmentScaleOverrides(count, data.mPosOverrides); - data.mActiveScaleOverride = scale; - joint_override = true; - } - if (joint_override) - { - joint_overrides[pJoint->getName()] = data; - } - } - - // Attachment points - for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - const LLViewerJointAttachment *attachment_pt = (*iter).second; - if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos, mesh_id)) - { - LLAttachmentOverrideData data; - attachment_pt->getAllAttachmentPosOverrides(count, data.mPosOverrides); - data.mActivePosOverride = pos; - attach_overrides[attachment_pt->getName()] = data; - } - } -} - //----------------------------------------------------------------------------- // removeAttachmentOverridesForObject //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 53a1d48d72..00dccc5d12 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -36,25 +36,23 @@ #include <boost/signals2/trackable.hpp> #include "llavatarappearance.h" -#include "llavatarappearancedefines.h" -#include "llavatarrendernotifier.h" -#include "llcontrol.h" -#include "llcharacter.h" #include "llchat.h" #include "lldrawpoolalpha.h" -#include "lldriverparam.h" -#include "lljointoverridedata.h" -#include "llrendertarget.h" -#include "llrigginginfo.h" -#include "lltexglobalcolor.h" +#include "llviewerobject.h" +#include "llcharacter.h" +#include "llcontrol.h" #include "llviewerjointmesh.h" #include "llviewerjointattachment.h" -#include "llviewerobject.h" -#include "llviewerstats.h" +#include "llrendertarget.h" +#include "llavatarappearancedefines.h" +#include "lltexglobalcolor.h" +#include "lldriverparam.h" #include "llviewertexlayer.h" -#include "llvovolume.h" - #include "material_codes.h" // LL_MCODE_END +#include "llrigginginfo.h" +#include "llviewerstats.h" +#include "llvovolume.h" +#include "llavatarrendernotifier.h" extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; @@ -217,8 +215,6 @@ public: void rebuildAttachmentOverrides(); void updateAttachmentOverrides(); void showAttachmentOverrides(bool verbose = false) const; - void getAttachmentOverrides(joint_override_data_map_t& joint_overrides, - attach_override_data_map_t& attach_overrides) const; void getAttachmentOverrideNames(std::set<std::string>& pos_names, std::set<std::string>& scale_names) const; 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 9009eeeb04..a69fa8c57c 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1304,62 +1304,23 @@ height="100" left_delta="0" top_pad="0" - width="310"> + width="330"> <scroll_list.columns - label="*" - name="override" - relative_width="0.22" /> + label="Model" + name="model_name" + relative_width="0.40" /> <scroll_list.columns label="X" name="axis_x" - relative_width="0.26" /> + relative_width="0.20" /> <scroll_list.columns label="Y" name="axis_y" - relative_width="0.26" /> + relative_width="0.20" /> <scroll_list.columns label="Z" name="axis_z" - relative_width="0.26" /> - </scroll_list> - <text - layout="topleft" - follows="top|left" - height="15" - left_delta="0" - name="scale_overrides_descr" - top_pad="3" - width="300"> - Scale overrides for joint '[JOINT]': - </text> - <scroll_list - layout="topleft" - follows="top|left" - name="scale_overrides_list" - column_padding="0" - draw_heading="true" - draw_stripes="false" - heading_height="23" - height="100" - left_delta="0" - top_pad="0" - width="310"> - <scroll_list.columns - label="*" - name="override" - relative_width="0.22" /> - <scroll_list.columns - label="X" - name="axis_x" - relative_width="0.26" /> - <scroll_list.columns - label="Y" - name="axis_y" - relative_width="0.26" /> - <scroll_list.columns - label="Z" - name="axis_z" - relative_width="0.26" /> + relative_width="0.20" /> </scroll_list> </panel> <panel -- cgit v1.2.3 From 6a3cb73009bccdef6ae1fbb5d8b632f90343ad91 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 10 Feb 2020 18:29:52 +0200 Subject: SL-379 Joint overrides tab --- indra/llcharacter/lljoint.cpp | 2 +- indra/llcharacter/lljoint.h | 2 + indra/newview/llfloatermodelpreview.cpp | 87 ++++++++++++++-------- indra/newview/llfloatermodelpreview.h | 7 +- .../skins/default/xui/en/floater_model_preview.xml | 14 +++- 5 files changed, 76 insertions(+), 36 deletions(-) diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 441ef1a352..bf99db2ce4 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -407,7 +407,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; } diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 6f69786f53..79d9637f21 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: diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c791ca8e77..b30054c818 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -641,17 +641,14 @@ void LLFloaterModelPreview::onJointListSelection() std::string label = selected->getValue().asString(); LLJointOverrideData &data = mJointOverrides[display_lod][label]; populate_list_with_map(joints_pos, data.mPosOverrides); - //populate_list_with_vectors(joints_scale, data.mScaleOverrides, data.mActiveScaleOverride); joint_pos_descr->setTextArg("[JOINT]", label); - //joint_scale_descr->setTextArg("[JOINT]", label); } else { // temporary value (shouldn't happen) std::string label = "mPelvis"; joint_pos_descr->setTextArg("[JOINT]", label); - //joint_scale_descr->setTextArg("[JOINT]", label); } } @@ -1433,7 +1430,6 @@ void LLFloaterModelPreview::addStringToLog(const std::ostringstream& strm, bool } } - void LLFloaterModelPreview::clearOverridesTab() { LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); @@ -1446,6 +1442,16 @@ void LLFloaterModelPreview::clearOverridesTab() } } +void LLFloaterModelPreview::resetOverridesTab() +{ + clearOverridesTab(); + + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mJointOverrides[i].clear(); + } +} + void LLFloaterModelPreview::showOverridesTab() { S32 display_lod = mModelPreview->mPreviewLOD; @@ -1453,11 +1459,13 @@ void LLFloaterModelPreview::showOverridesTab() { return; } - - // Todo: Are overrides identical for all lods? + + // 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 list + // 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) @@ -1473,10 +1481,11 @@ void LLFloaterModelPreview::showOverridesTab() 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).inRange(-F_APPROXIMATELY_ZERO, F_APPROXIMATELY_ZERO)) + && (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). + // 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; @@ -1486,36 +1495,45 @@ void LLFloaterModelPreview::showOverridesTab() } } } - + LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); S32 index = mTabContainer->getIndexForPanel(panel); mTabContainer->enableTabButton(index, true); - LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); - 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) + if (joints_list->isEmpty()) { - const std::string& listName = joint_iter->first; + // Populate table + S32 conflicts = 0; + joint_override_data_map_t::iterator joint_iter = mJointOverrides[display_lod].begin(); + joint_override_data_map_t::iterator joint_end = mJointOverrides[display_lod].end(); + while (joint_iter != joint_end) + { + const std::string& listName = joint_iter->first; - LLScrollListItem::Params item_params; - item_params.value(listName); + LLScrollListItem::Params item_params; + item_params.value(listName); - LLScrollListCell::Params cell_params; - cell_params.font = LLFontGL::getFontSansSerif(); - cell_params.value = listName; - if (joint_iter->second.mHasConflicts) - { - cell_params.color = LLColor4::orange; - } + LLScrollListCell::Params cell_params; + cell_params.font = LLFontGL::getFontSansSerif(); + cell_params.value = listName; + if (joint_iter->second.mHasConflicts) + { + cell_params.color = LLColor4::orange; + conflicts++; + } - item_params.columns.add(cell_params); + item_params.columns.add(cell_params); - joints_list->addRow(item_params, ADD_BOTTOM); - joint_iter++; + joints_list->addRow(item_params, ADD_BOTTOM); + joint_iter++; + } + joints_list->selectFirstItem(); + + LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("conflicts_description"); + joint_pos_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts)); + joint_pos_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size())); } - joints_list->selectFirstItem(); } void LLFloaterModelPreview::hideOverridesTab() @@ -2451,7 +2469,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } else { - fmp->clearOverridesTab(); + fmp->resetOverridesTab(); fmp->hideOverridesTab(); } @@ -4051,6 +4069,8 @@ void LLModelPreview::addEmptyFace( LLModel* pTarget ) //----------------------------------------------------------------------------- // 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(); @@ -4824,6 +4844,13 @@ void LLModelPreview::setPreviewLOD(S32 lod) mFMP->childSetColor(lod_triangles_name[i], color); mFMP->childSetColor(lod_vertices_name[i], color); } + + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)mFMP; + if (fmp) + { + // make preview repopulate tab + fmp->clearOverridesTab(); + } } refresh(); updateStatusMessages(); @@ -4845,7 +4872,7 @@ void LLFloaterModelPreview::onReset(void* user_data) LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); fmp->clearLogTab(); - fmp->clearOverridesTab(); + fmp->resetOverridesTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index f53478f31b..2adbfc1e79 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -107,9 +107,10 @@ public: 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 clearOverridesTab(); - void showOverridesTab(); + static void addStringToLog(const std::ostringstream& strm, bool flash); + void clearOverridesTab(); // clears table + void resetOverridesTab(); // clears table and cleans all data + void showOverridesTab(); // populates table and data as nessesary void hideOverridesTab(); void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); 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 a69fa8c57c..9ebcb0c09d 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1279,10 +1279,20 @@ draw_stripes="false" commit_on_selection_change="true" heading_height="23" - height="253" + height="238" left="6" top_pad="0" - width="150"/> + width="200"/> + <text + layout="topleft" + follows="top|left" + height="15" + left="6" + name="conflicts_description" + top_pad="2" + width="200"> + [CONFLICTS] conflicts in [JOINTS_COUNT] joints + </text> <text layout="topleft" follows="top|left" -- cgit v1.2.3 From e66e31f380563962429c8b285f1aa5dabf8ea5d2 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Sat, 22 Feb 2020 19:24:13 +0200 Subject: post-merge buildfix --- indra/newview/llfloatermodelpreview.h | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index d7fea67e60..c359722431 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -235,6 +235,7 @@ private: 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. -- cgit v1.2.3 From eaa9b152bfe9b5da44f724ddce1a2ecc86dc61bf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 27 Mar 2020 19:05:23 +0200 Subject: SL-307 Implemented ability to specify color and changed flashing color --- indra/llui/llbutton.cpp | 5 +++++ indra/llui/llbutton.h | 1 + indra/llui/lltabcontainer.cpp | 11 +++++++++++ indra/llui/lltabcontainer.h | 3 ++- indra/newview/llfloatermodelpreview.cpp | 5 ++++- indra/newview/skins/default/xui/en/floater_script_debug.xml | 3 ++- 6 files changed, 25 insertions(+), 3 deletions(-) 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/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 2a221fc19c..750a3aff9c 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -260,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); @@ -1641,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 8f93f1c47d..5339bec3dd 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -111,7 +111,7 @@ public: Optional<bool> open_tabs_on_drag_and_drop; /** - * Open tabs on hover in drag and drop situations + * Enable tab flashing */ Optional<bool> enable_tabs_flashing; @@ -203,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); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index e694340b16..f386e9e305 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1583,7 +1583,10 @@ void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash if (flash && mTabContainer->getCurrentPanel() != panel) { - mTabContainer->setTabPanelFlashing(panel, true); + // 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); } } 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> -- cgit v1.2.3 From 46c76eabb86fff6ca6c8352e10988b15c20ef8a6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 30 Mar 2020 15:14:44 +0300 Subject: SL-379 Do not disable tabs --- indra/newview/llfloatermodelpreview.cpp | 20 +++----------------- indra/newview/llfloatermodelpreview.h | 3 +-- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f386e9e305..d53b0c1155 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -407,13 +407,11 @@ BOOL LLFloaterModelPreview::postBuild() // Disable Overrides tab untill it has something to show and set callbacks LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); S32 index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, false); panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); // Disable Logs tab untill it has something to show panel = mTabContainer->getPanelByName("logs_panel"); index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, false); if (LLConvexDecomposition::getInstance() != NULL) { @@ -1459,7 +1457,7 @@ void LLFloaterModelPreview::resetOverridesTab() } } -void LLFloaterModelPreview::showOverridesTab() +void LLFloaterModelPreview::updateOverridesTab() { S32 display_lod = mModelPreview->mPreviewLOD; if (mModelPreview->mModel[display_lod].empty()) @@ -1504,8 +1502,6 @@ void LLFloaterModelPreview::showOverridesTab() } LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, true); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); if (joints_list->isEmpty()) @@ -1543,13 +1539,6 @@ void LLFloaterModelPreview::showOverridesTab() } } -void LLFloaterModelPreview::hideOverridesTab() -{ - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, false); -} - //----------------------------------------------------------------------------- // addStringToLogTab() //----------------------------------------------------------------------------- @@ -1569,8 +1558,6 @@ void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash } LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); - mTabContainer->enableTabButton(index, true); // Make sure we have space for new string S32 editor_text_len = mUploadLogText->getLength(); @@ -2480,7 +2467,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) else { fmp->resetOverridesTab(); - fmp->hideOverridesTab(); } if (lock_scale_if_joint_position) @@ -4231,7 +4217,7 @@ BOOL LLModelPreview::render() mFMP->childEnable("lock_scale_if_joint_position"); if (fmp) { - fmp->showOverridesTab(); + fmp->updateOverridesTab(); } } else @@ -4240,7 +4226,7 @@ BOOL LLModelPreview::render() mFMP->childSetValue("lock_scale_if_joint_position", false); if (fmp) { - fmp->hideOverridesTab(); + fmp->resetOverridesTab(); } } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index c359722431..f64a7b6feb 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -110,8 +110,7 @@ public: static void addStringToLog(const std::ostringstream& strm, bool flash); void clearOverridesTab(); // clears table void resetOverridesTab(); // clears table and cleans all data - void showOverridesTab(); // populates table and data as nessesary - void hideOverridesTab(); + void updateOverridesTab(); // populates table and data as nessesary void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void setPreviewLOD(S32 lod); -- cgit v1.2.3 From acb6e12135452d8d4e53a9a61e1fb50cdeec2469 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 30 Mar 2020 16:47:54 +0300 Subject: SL-379 Remake Overrides tab into Avatar --- indra/newview/llfloatermodelpreview.cpp | 44 ++-- indra/newview/llfloatermodelpreview.h | 1 - .../skins/default/xui/en/floater_model_preview.xml | 222 ++++++++++----------- 3 files changed, 136 insertions(+), 131 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d53b0c1155..f99b42ab2c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -346,6 +346,10 @@ BOOL LLFloaterModelPreview::postBuild() childSetVisible("skin_too_many_joints", false); childSetVisible("skin_unknown_joint", false); + childSetVisible("warning_title", false); + childSetVisible("warning_message", false); + childSetVisible("status", false); + initDecompControls(); LLView* preview_panel = getChild<LLView>("preview_panel"); @@ -656,6 +660,7 @@ void LLFloaterModelPreview::onJointListSelection() joint_pos_descr->setTextArg("[JOINT]", label); } + // Note: We can make a version of renderBones() to highlight selected joint } void LLFloaterModelPreview::onDescriptionKeystroke(LLUICtrl* ctrl) @@ -1440,21 +1445,22 @@ void LLFloaterModelPreview::clearOverridesTab() LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); joints_list->deleteAllItems(); + LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); + joints_pos->deleteAllItems(); + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { mJointOverrides[i].clear(); } -} -void LLFloaterModelPreview::resetOverridesTab() -{ - clearOverridesTab(); + 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)); - for (U32 i = 0; i < LLModel::NUM_LODS; ++i) - { - mJointOverrides[i].clear(); - } + + 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::updateOverridesTab() @@ -1507,6 +1513,10 @@ void LLFloaterModelPreview::updateOverridesTab() 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(); @@ -1520,8 +1530,14 @@ void LLFloaterModelPreview::updateOverridesTab() 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++; } @@ -1533,9 +1549,9 @@ void LLFloaterModelPreview::updateOverridesTab() } joints_list->selectFirstItem(); - LLTextBox *joint_pos_descr = panel->getChild<LLTextBox>("conflicts_description"); - joint_pos_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts)); - joint_pos_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size())); + 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())); } } @@ -2466,7 +2482,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } else { - fmp->resetOverridesTab(); + fmp->clearOverridesTab(); } if (lock_scale_if_joint_position) @@ -4226,7 +4242,7 @@ BOOL LLModelPreview::render() mFMP->childSetValue("lock_scale_if_joint_position", false); if (fmp) { - fmp->resetOverridesTab(); + fmp->clearOverridesTab(); } } @@ -4868,7 +4884,7 @@ void LLFloaterModelPreview::onReset(void* user_data) LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); fmp->clearLogTab(); - fmp->resetOverridesTab(); + fmp->clearOverridesTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index f64a7b6feb..d079a3d782 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -109,7 +109,6 @@ public: static void addStringToLog(const std::string& str, bool flash); static void addStringToLog(const std::ostringstream& strm, bool flash); void clearOverridesTab(); // clears table - void resetOverridesTab(); // clears table and cleans all data void updateOverridesTab(); // populates table and data as nessesary void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); 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 9ebcb0c09d..053c482831 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -47,12 +47,12 @@ <panel follows="top|left" - height="580" + height="595" layout="topleft" left="3" name="left_panel" top_pad="0" - width="630"> + width="635"> <panel follows="all" height="50" @@ -83,9 +83,9 @@ </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" @@ -100,12 +100,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="619" /> + width="628" /> <text follows="left|top" height="18" @@ -696,7 +696,7 @@ left="10" name="lod_tab_border" top_pad="20" - width="605" /> + width="614" /> <check_box follows="top|left" height="15" @@ -738,12 +738,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" @@ -1113,12 +1113,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" @@ -1165,109 +1165,94 @@ 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"/> - <text - follows="top|left" - height="17" - left="40" - name="skin_too_many_joints" - text_color="Orange" - top_pad="-2" - width="150"> - Too many skinned joints - </text> - <text - follows="top|left" - height="17" - left="40" - name="skin_unknown_joint" - text_color="Orange" - top_pad="-17" - width="150"> - Model has an unknown joint(s) - </text> - <check_box - follows="top|left" - height="15" - label="Include joint positions" - label_text.text_color="White" - name="upload_joints" - left_delta="-20" - top_pad="1"/> - <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="16"/> - <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="overrides_panel" - title="Overrides"> + title="Avatar"> <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" - name="log_tab_border" + name="avatar_tab_border" top_pad="0" - width="619" /> + 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="6" + left="20" name="joints_descr" - top="4" - width="300"> + top="73" + width="150"> Joints: </text> <scroll_list @@ -1279,15 +1264,15 @@ draw_stripes="false" commit_on_selection_change="true" heading_height="23" - height="238" - left="6" + height="199" + left_delta="0" top_pad="0" width="200"/> <text layout="topleft" follows="top|left" height="15" - left="6" + left_delta="0" name="conflicts_description" top_pad="2" width="200"> @@ -1299,7 +1284,7 @@ height="15" left_pad="5" name="pos_overrides_descr" - top="4" + top="73" width="300"> Position overrides for joint '[JOINT]': </text> @@ -1314,23 +1299,23 @@ height="100" left_delta="0" top_pad="0" - width="330"> + width="385"> <scroll_list.columns label="Model" name="model_name" - relative_width="0.40" /> + relative_width="0.49" /> <scroll_list.columns label="X" name="axis_x" - relative_width="0.20" /> + relative_width="0.17" /> <scroll_list.columns label="Y" name="axis_y" - relative_width="0.20" /> + relative_width="0.17" /> <scroll_list.columns label="Z" name="axis_z" - relative_width="0.20" /> + relative_width="0.17" /> </scroll_list> </panel> <panel @@ -1341,12 +1326,12 @@ <view_border bevel_style="none" follows="top|left" - height="275" + height="306" layout="topleft" left="3" name="log_tab_border" top_pad="0" - width="619" /> + width="628" /> <text_editor type="string" length="1" @@ -1355,10 +1340,10 @@ font="SansSerif" ignore_tab="false" layout="topleft" - height="275" + height="306" left="4" top="0" - right="-11" + right="-1" max_length="65536" name="log_text" parse_urls="true" @@ -1371,7 +1356,7 @@ <panel follows="top|left|bottom" layout="topleft" - height="197" + height="195" left="4" border="true" name="weights_and_warning_panel" @@ -1611,7 +1596,7 @@ Analysed: name="warning_title" top_pad="5" text_color="DrYellow" - visible="false" + visible="true" width="40"> NOTE: </text> @@ -1622,13 +1607,18 @@ Analysed: 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="-1" left="6" name="status"> + <text + text_color="Yellow" + layout="topleft" + top_pad="-2" + left="6" + name="status"> [STATUS] </text> </panel> -- cgit v1.2.3 From aaddcc0b704f28555fbd4a1f6068f44242966295 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 30 Mar 2020 20:04:25 +0300 Subject: SL-307 A separator to see where model loading logs ends and other state starts --- indra/newview/llfloatermodelpreview.cpp | 4 ++++ indra/newview/skins/default/xui/en/floater_model_preview.xml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f99b42ab2c..b0dfe19451 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -2625,6 +2625,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(); 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 053c482831..aeed3b4623 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -39,11 +39,11 @@ <string name="simplifying">Simplifying...</string> <string name="tbd">TBD</string> - <!-- Warnings from model loader--> + <!-- 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" -- cgit v1.2.3 From 3c2f3edb5fefff69e370f4e427dd23236cf8edbf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 31 Mar 2020 15:40:48 +0300 Subject: SL-379 Render selected joint yellow when Avatar tab is open --- indra/newview/llfloatermodelpreview.cpp | 52 +++++++++++++--------- indra/newview/llfloatermodelpreview.h | 7 ++- indra/newview/llvoavatar.cpp | 21 +++++++-- indra/newview/llvoavatar.h | 2 +- .../skins/default/xui/en/floater_model_preview.xml | 2 +- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b0dfe19451..2a0e51f496 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -266,7 +266,8 @@ LLFloaterModelUploadBase(key), mUploadBtn(NULL), mCalculateBtn(NULL), mUploadLogText(NULL), -mTabContainer(NULL) +mTabContainer(NULL), +mAvatarTabIndex(0) { sInstance = this; mLastMouseX = 0; @@ -408,15 +409,10 @@ BOOL LLFloaterModelPreview::postBuild() mUploadLogText = getChild<LLViewerTextEditor>("log_text"); mTabContainer = getChild<LLTabContainer>("import_tab"); - // Disable Overrides tab untill it has something to show and set callbacks - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); - S32 index = mTabContainer->getIndexForPanel(panel); + LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + mAvatarTabIndex = mTabContainer->getIndexForPanel(panel); panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); - // Disable Logs tab untill it has something to show - panel = mTabContainer->getPanelByName("logs_panel"); - index = mTabContainer->getIndexForPanel(panel); - if (LLConvexDecomposition::getInstance() != NULL) { mCalculateBtn->setClickedCallback(boost::bind(&LLFloaterModelPreview::onClickCalculateBtn, this)); @@ -635,7 +631,7 @@ void populate_list_with_map(LLScrollListCtrl *list, const std::map<std::string, void LLFloaterModelPreview::onJointListSelection() { S32 display_lod = mModelPreview->mPreviewLOD; - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + 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"); @@ -652,12 +648,14 @@ void LLFloaterModelPreview::onJointListSelection() 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 @@ -1440,14 +1438,13 @@ void LLFloaterModelPreview::addStringToLog(const std::ostringstream& strm, bool } } -void LLFloaterModelPreview::clearOverridesTab() +void LLFloaterModelPreview::clearAvatarTab() { - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + 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(); - + joints_pos->deleteAllItems(); mSelectedJointName.clear(); for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { @@ -1463,11 +1460,12 @@ void LLFloaterModelPreview::clearOverridesTab() joint_pos_descr->setTextArg("[JOINT]", std::string("mPelvis")); // Might be better to hide it } -void LLFloaterModelPreview::updateOverridesTab() +void LLFloaterModelPreview::updateAvatarTab() { S32 display_lod = mModelPreview->mPreviewLOD; if (mModelPreview->mModel[display_lod].empty()) { + mSelectedJointName.clear(); return; } @@ -1507,7 +1505,7 @@ void LLFloaterModelPreview::updateOverridesTab() } } - LLPanel *panel = mTabContainer->getPanelByName("overrides_panel"); + LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); if (joints_list->isEmpty()) @@ -1548,6 +1546,11 @@ void LLFloaterModelPreview::updateOverridesTab() 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)); @@ -2482,7 +2485,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } else { - fmp->clearOverridesTab(); + fmp->clearAvatarTab(); } if (lock_scale_if_joint_position) @@ -4237,7 +4240,7 @@ BOOL LLModelPreview::render() mFMP->childEnable("lock_scale_if_joint_position"); if (fmp) { - fmp->updateOverridesTab(); + fmp->updateAvatarTab(); } } else @@ -4246,7 +4249,7 @@ BOOL LLModelPreview::render() mFMP->childSetValue("lock_scale_if_joint_position", false); if (fmp) { - fmp->clearOverridesTab(); + fmp->clearAvatarTab(); } } @@ -4774,7 +4777,14 @@ 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(); @@ -4865,7 +4875,7 @@ void LLModelPreview::setPreviewLOD(S32 lod) if (fmp) { // make preview repopulate tab - fmp->clearOverridesTab(); + fmp->clearAvatarTab(); } } refresh(); @@ -4888,7 +4898,7 @@ void LLFloaterModelPreview::onReset(void* user_data) LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); fmp->clearLogTab(); - fmp->clearOverridesTab(); + fmp->clearAvatarTab(); LLModelPreview* mp = fmp->mModelPreview; std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index d079a3d782..1542e97160 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -108,8 +108,8 @@ public: 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 clearOverridesTab(); // clears table - void updateOverridesTab(); // populates table and data as nessesary + 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); @@ -249,6 +249,9 @@ private: 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]; }; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b524db478e..32e6535465 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/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index aeed3b4623..da4190c4fc 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1169,7 +1169,7 @@ <panel label="Overrides" layout="topleft" - name="overrides_panel" + name="avatar_panel" title="Avatar"> <view_border bevel_style="none" -- cgit v1.2.3 From 8a630120540146c8724994dbc116a833a88ac2d6 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Wed, 15 Apr 2020 08:42:05 +0300 Subject: SL-10642 LLModelPreview logging fix --- indra/newview/llfloatermodelpreview.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 1542e97160..5d86ebc6a6 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -268,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; -- cgit v1.2.3 From 3ab32456a0e2fde64b405ac9d53150dfe9561ffe Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 15 Apr 2020 14:30:33 +0300 Subject: SL-307 ImporterDebug is now logged into in-viewer log --- indra/newview/llfloatermodelpreview.cpp | 116 ++++++++++++++++++++++---------- indra/newview/llfloatermodelpreview.h | 1 + 2 files changed, 81 insertions(+), 36 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 2a0e51f496..02ebac3b51 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1612,6 +1612,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mModelNoErrors( true ) , mLastJointUpdate( false ) , mHasDegenerate( false ) +, mImporterDebug(LLCachedControl<bool>(gSavedSettings, "ImporterDebug", false)) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -1821,7 +1822,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) @@ -1901,9 +1901,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; @@ -1943,9 +1948,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; } @@ -1958,29 +1968,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; } @@ -1992,9 +2011,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); } } } @@ -2061,9 +2083,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" ); @@ -2526,7 +2551,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } else { - BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); if (!legacyMatching) { @@ -2539,9 +2563,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; } @@ -2565,9 +2592,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) @@ -2589,7 +2619,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) case LLModel::LOD_HIGH: break; } - if (importerDebug) + if (mImporterDebug) { std::ostringstream out; out << "Loded model name " << mModel[loaded_lod][idx]->mLabel; @@ -3195,20 +3225,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++; } } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 5d86ebc6a6..6f78d534f3 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -457,6 +457,7 @@ private: JointTransformMap mJointTransformMap; LLPointer<LLVOAvatar> mPreviewAvatar; + LLCachedControl<bool> mImporterDebug; }; #endif // LL_LLFLOATERMODELPREVIEW_H -- cgit v1.2.3 From 884d5024a3b2b7b65f2e05e29073ccab7fac6762 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 17 Apr 2020 17:19:55 +0300 Subject: SL-13061 Fixed missing scroll handling --- indra/newview/llfloatermodelpreview.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 02ebac3b51..5895ebe7d7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1015,8 +1015,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*/ -- cgit v1.2.3 From b0b155efefe224bd645a28efc24eb8b0b3e5580b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 17 Apr 2020 17:58:58 +0300 Subject: SL-13062 Fixed Scaled-down 'Upload Model' floater having a frame at the bottom The way legacy_header_height works is just wrong... --- indra/newview/skins/default/xui/en/floater_model_preview.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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 da4190c4fc..e8c64dfef7 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -4,13 +4,14 @@ can_drag_on_left="false" can_minimize="true" can_resize="true" - height="600" - min_height="600" + 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> @@ -51,7 +52,7 @@ layout="topleft" left="3" name="left_panel" - top_pad="0" + top_pad="25" width="635"> <panel follows="all" @@ -1630,7 +1631,7 @@ Analysed: left="640" name="lod_label" text_color="White" - top="4" + top="29" height="15" width="290"> Preview: -- cgit v1.2.3 From a8df6762ff88458916397b9707f6954b2714e14d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 17 Apr 2020 19:24:55 +0300 Subject: SL-13065 Fixed missing error and infinite cycle caused by too much logging --- indra/newview/llfloatermodelpreview.cpp | 35 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 5895ebe7d7..d1056662ca 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -349,7 +349,6 @@ BOOL LLFloaterModelPreview::postBuild() childSetVisible("warning_title", false); childSetVisible("warning_message", false); - childSetVisible("status", false); initDecompControls(); @@ -1579,23 +1578,41 @@ void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash return; } - LLPanel* panel = mTabContainer->getPanelByName("logs_panel"); - // 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)) { - editor_text_len -= mUploadLogText->removeFirstLine(); + 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 && mTabContainer->getCurrentPanel() != panel) + if (flash) { - // 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); + 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); + } } } -- cgit v1.2.3 From 9aa7485d61452bbaa4644cb15fa60f922d7d1e5b Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy <alihatskiy@productengine.com> Date: Tue, 21 Apr 2020 13:36:03 +0300 Subject: SL-13075 Fixed the uploaded model preview size --- indra/newview/llfloatermodelpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 99f5fa35cd..a27272fbfe 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -455,11 +455,11 @@ void LLFloaterModelPreview::initModelPreview() 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) + while ((tex_width << 1) < max_width) { tex_width <<= 1; } - while ((tex_height << 1) <= max_height) + while ((tex_height << 1) < max_height) { tex_height <<= 1; } -- cgit v1.2.3 From 1f8f3d13d0baf7668696d98064a6d65af52d036b Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 21 Apr 2020 15:41:42 +0300 Subject: SL-10613 The Smooth parameter should be 0 by default --- indra/newview/llfloatermodelpreview.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a27272fbfe..54ab245089 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1278,7 +1278,8 @@ void LLFloaterModelPreview::initDecompControls() float max = param[i].mDetails.mRange.mHigh.mFloat; float delta = param[i].mDetails.mRange.mDelta.mFloat; - if ("Cosine%" == name) + bool is_smooth_cb = ("Cosine%" == name); + if (is_smooth_cb) { createSmoothComboBox(combo_box, min, max); } @@ -1290,7 +1291,7 @@ void LLFloaterModelPreview::initDecompControls() combo_box->add(label, value, ADD_BOTTOM, true); } } - combo_box->setValue(param[i].mDefault.mFloat); + combo_box->setValue(is_smooth_cb ? 0: param[i].mDefault.mFloat); combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); } } -- cgit v1.2.3 From 311921cad63175b276fefae4de3dbed8bce98802 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 21 Apr 2020 17:33:14 +0300 Subject: SL-13064 Artifacts on the preview with physics --- indra/newview/llfloatermodelpreview.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 54ab245089..264ba99170 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4597,7 +4597,8 @@ BOOL LLModelPreview::render() } } } - } + gGL.popMatrix(); + } // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] if (pass > 0 && mHasDegenerate) @@ -4642,8 +4643,7 @@ BOOL LLModelPreview::render() genBuffers(LLModel::LOD_PHYSICS, false); } - auto num_degenerate = 0; - auto num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); + U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); for (U32 v = 0; v < num_models; ++v) { LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; @@ -4667,7 +4667,6 @@ BOOL LLModelPreview::render() 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); -- cgit v1.2.3 From d38fd1e7c3a48260f670e135501bba68d9d4dc51 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 21 Apr 2020 18:55:29 +0300 Subject: SL-13081 Model is unnaturally grey --- indra/newview/app_settings/shaders/class1/objects/previewV.glsl | 1 - 1 file changed, 1 deletion(-) diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl index 2cf17acf6b..4bb588335a 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -93,6 +93,5 @@ 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; } -- cgit v1.2.3 From 462b0b1c2dbf68f7a45fef427de13f59b7e078a1 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Wed, 22 Apr 2020 15:57:34 +0300 Subject: =?UTF-8?q?SL-13066=20FIXED=20Model=20preview=20with=20is=20displa?= =?UTF-8?q?yed=20when=20the=20=E2=80=98Upload=20Model=E2=80=99=20floater?= =?UTF-8?q?=20is=20minimized?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- indra/newview/llfloatermodelpreview.cpp | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 264ba99170..3564d7c241 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -886,36 +886,9 @@ void LLFloaterModelPreview::draw() childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); - if (mModelPreview->lodsReady()) + if (!isMinimized() && mModelPreview->lodsReady()) { - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - - LLView* preview_panel = getChild<LLView>("preview_panel"); - - 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); + draw3dPreview(); } } -- cgit v1.2.3 From 2b459cc80ee5bc3bf29e54523dc2ddccb51ab798 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 22 Apr 2020 17:30:01 +0300 Subject: SL-13078 Split LLModelPreview and LLFloaterModelPreview into separate files --- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloatermodelpreview.cpp | 3607 +------------------------------ indra/newview/llfloatermodelpreview.h | 232 +- indra/newview/llmodelpreview.cpp | 3507 ++++++++++++++++++++++++++++++ indra/newview/llmodelpreview.h | 308 +++ 5 files changed, 3867 insertions(+), 3789 deletions(-) create mode 100644 indra/newview/llmodelpreview.cpp create mode 100644 indra/newview/llmodelpreview.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c9d5fb89ba..65cee71b1d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -399,6 +399,7 @@ set(viewer_SOURCE_FILES llmenuoptionpathfindingrebakenavmesh.cpp llmeshrepository.cpp llmimetypes.cpp + llmodelpreview.cpp llmorphview.cpp llmoveview.cpp llmutelist.cpp @@ -1025,6 +1026,7 @@ set(viewer_HEADER_FILES llmenuoptionpathfindingrebakenavmesh.h llmeshrepository.h llmimetypes.h + llmodelpreview.h llmorphview.h llmoveview.h llmutelist.h diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3564d7c241..9c62680dde 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -27,7 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llmodelloader.h" -#include "lldaeloader.h" +#include "llmodelpreview.h" #include "llfloatermodelpreview.h" @@ -40,13 +40,7 @@ #include "llagent.h" #include "llbutton.h" #include "llcombobox.h" -#include "lldatapacker.h" -#include "lldrawable.h" -#include "llrender.h" -#include "llface.h" #include "llfocusmgr.h" -#include "llfloaterperms.h" -#include "lliconctrl.h" #include "llmatrix4a.h" #include "llmenubutton.h" #include "llmeshrepository.h" @@ -57,17 +51,10 @@ #include "lltoolmgr.h" #include "llui.h" #include "llvector4a.h" -#include "llviewercamera.h" #include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" #include "pipeline.h" -#include "lluictrlfactory.h" #include "llviewercontrol.h" -#include "llviewermenu.h" #include "llviewermenufile.h" -#include "llviewerregion.h" -#include "llviewertexturelist.h" #include "llstring.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -81,21 +68,14 @@ #include "llvfile.h" #include "llvfs.h" #include "llcallbacklist.h" -#include "llviewerobjectlist.h" -#include "llanimationstates.h" #include "llviewertexteditor.h" #include "llviewernetwork.h" -#include "llviewershadermgr.h" -#include "glod/glod.h" -#include <boost/algorithm/string.hpp> //static S32 LLFloaterModelPreview::sUploadAmount = 10; LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; -bool LLModelPreview::sIgnoreLoadedCallback = false; - // "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01 // But according to the UI spec for upload model floater, this parameter // should be represented by Retain spinner with values from 1 to 100 by 1. @@ -109,111 +89,17 @@ const double RETAIN_COEFFICIENT = 100; // So this const is used as a size of Smooth combobox list. const S32 SMOOTH_VALUES_NUMBER = 10; -const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size); - - -std::string lod_name[NUM_LOD+1] = -{ - "lowest", - "low", - "medium", - "high", - "I went off the end of the lod_name array. Me so smart." -}; - -std::string lod_triangles_name[NUM_LOD+1] = -{ - "lowest_triangles", - "low_triangles", - "medium_triangles", - "high_triangles", - "I went off the end of the lod_triangles_name array. Me so smart." -}; - -std::string lod_vertices_name[NUM_LOD+1] = -{ - "lowest_vertices", - "low_vertices", - "medium_vertices", - "high_vertices", - "I went off the end of the lod_vertices_name array. Me so smart." -}; - -std::string lod_status_name[NUM_LOD+1] = -{ - "lowest_status", - "low_status", - "medium_status", - "high_status", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_icon_name[NUM_LOD+1] = +class LLMeshFilePicker : public LLFilePickerThread { - "status_icon_lowest", - "status_icon_low", - "status_icon_medium", - "status_icon_high", - "I went off the end of the lod_status_name array. Me so smart." -}; - -std::string lod_status_image[NUM_LOD+1] = -{ - "ModelImport_Status_Good", - "ModelImport_Status_Warning", - "ModelImport_Status_Error", - "I went off the end of the lod_status_image array. Me so smart." -}; +public: + LLMeshFilePicker(LLModelPreview* mp, S32 lod); + virtual void notify(const std::vector<std::string>& filenames); -std::string lod_label_name[NUM_LOD+1] = -{ - "lowest_label", - "low_label", - "medium_label", - "high_label", - "I went off the end of the lod_label_name array. Me so smart." +private: + LLModelPreview* mMP; + S32 mLOD; }; -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; - return TRUE; - } - - return FALSE; -} - -LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) -{ - LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); - - if (texture) - { - if (texture->getDiscardLevel() > -1) - { - gGL.getTexUnit(0)->bind(texture, true); - return texture; - } - } - - return NULL; -} - -std::string stripSuffix(std::string name) -{ - if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1)) - { - return name.substr(0, name.rfind('_')); - } - return name; -} - LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) : LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) { @@ -234,30 +120,6 @@ void LLMeshFilePicker::notify(const std::vector<std::string>& filenames) } } -void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) -{ - LLModelLoader::scene::iterator base_iter = scene.begin(); - bool found = false; - while (!found && (base_iter != scene.end())) - { - matOut = base_iter->first; - - LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); - while (!found && (base_instance_iter != base_iter->second.end())) - { - LLModelInstance& base_instance = *base_instance_iter++; - LLModel* base_model = base_instance.mModel; - - if (base_model && (base_model->mLabel == name_to_match)) - { - baseModelOut = base_model; - return; - } - } - base_iter++; - } -} - //----------------------------------------------------------------------------- // LLFloaterModelPreview() //----------------------------------------------------------------------------- @@ -564,13 +426,6 @@ void LLFloaterModelPreview::onClickCalculateBtn() bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); bool lock_scale_if_joint_position = childGetValue("lock_scale_if_joint_position").asBoolean(); - if (upload_joint_positions) - { - // Diagnostic message showing list of joints for which joint offsets are defined. - // FIXME - given time, would be much better to put this in the UI, in updateStatusMessages(). - mModelPreview->getPreviewAvatar()->showAttachmentOverrides(); - } - mUploadModelUrl.clear(); mModelPhysicsFee.clear(); @@ -1590,195 +1445,6 @@ void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool flash } } -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() -, mLodsQuery() -, mLodsWithParsingError() -, mPelvisZOffset( 0.0f ) -, 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; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 0; - mModelLoader = NULL; - mMaxTriangleLimit = 0; - mDirty = false; - mGenLOD = false; - mLoading = false; - mLoadState = LLModelLoader::STARTING; - mGroup = 0; - mLODFrozen = false; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; - - for (U32 i = 0; i < LLModel::NUM_LODS; ++i) - { - mRequestedTriangleCount[i] = 0; - mRequestedCreaseAngle[i] = -1.f; - mRequestedLoDMode[i] = 0; - mRequestedErrorThreshold[i] = 0.f; - mRequestedBuildOperator[i] = 0; - mRequestedQueueMode[i] = 0; - mRequestedBorderMode[i] = 0; - mRequestedShareTolerance[i] = 0.f; - } - - mViewOption["show_textures"] = false; - - mFMP = fmp; - - mHasPivot = false; - mModelPivot = LLVector3( 0.0f, 0.0f, 0.0f ); - - glodInit(); - - createPreviewAvatar(); -} - -LLModelPreview::~LLModelPreview() -{ - // glod apparently has internal mem alignment issues that are angering - // the heap-check code in windows, these should be hunted down in that - // TP code, if possible - // - // kernel32.dll!HeapFree() + 0x14 bytes - // msvcr100.dll!free(void * pBlock) Line 51 C - // glod.dll!glodGetGroupParameteriv() + 0x119 bytes - // glod.dll!glodShutdown() + 0x77 bytes - // - //glodShutdown(); - if(mModelLoader) - { - mModelLoader->shutdown(); - } -} - -U32 LLModelPreview::calcResourceCost() -{ - assert_main_thread(); - - rebuildUploadData(); - - //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed. - if ( mFMP && mFMP->childGetValue("upload_skin").asBoolean() ) - { - bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); - if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) - { - mFMP->childDisable("ok_btn"); - } - } - - std::set<LLModel*> accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f; - - if ( mFMP && mFMP->childGetValue("upload_joints").asBoolean() ) - { - // FIXME if preview avatar ever gets reused, this fake mesh ID stuff will fail. - // see also call to addAttachmentPosOverride. - LLUUID fake_mesh_id; - fake_mesh_id.generate(); - getPreviewAvatar()->addPelvisFixup( mPelvisZOffset, fake_mesh_id ); - } - - F32 streaming_cost = 0.f; - F32 physics_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::Decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : - instance.mModel->mPhysics; - - //update instance skin info for each lods pelvisZoffset - for ( int j=0; j<LLModel::NUM_LODS; ++j ) - { - if ( instance.mLOD[j] ) - { - instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset; - } - } - - std::stringstream ostr; - LLSD ret = LLModel::writeModel(ostr, - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - mFMP->childGetValue("lock_scale_if_joint_position").asBoolean(), - TRUE, - FALSE, - instance.mModel->mSubmodelID); - - num_hulls += decomp.mHull.size(); - for (U32 i = 0; i < decomp.mHull.size(); ++i) - { - num_points += decomp.mHull[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; - - LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - LLVector3 scale = LLVector3(x_length, y_length, z_length); - - F32 radius = scale.length()*0.5f*debug_scale; - - LLMeshCostData costs; - if (gMeshRepo.getCostData(ret, costs)) - { - streaming_cost += costs.getRadiusBasedStreamingCost(radius); - } - } - } - - F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; - - mDetailsSignal(mPreviewScale[0]*scale, mPreviewScale[1]*scale, mPreviewScale[2]*scale, streaming_cost, physics_cost); - - updateStatusMessages(); - - return (U32) streaming_cost; -} - void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) { assert_main_thread(); @@ -1795,3247 +1461,70 @@ void LLFloaterModelPreview::setPreviewLOD(S32 lod) } } - -void LLModelPreview::rebuildUploadData() +void LLFloaterModelPreview::onBrowseLOD(S32 lod) { assert_main_thread(); - mUploadData.clear(); - mTextureSet.clear(); - - //fill uploaddata instance vectors from scene data - - std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString(); - - LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale"); - - F32 scale = scale_spinner->getValue().asReal(); - - LLMatrix4 scale_mat; - scale_mat.initScale(LLVector3(scale, scale, scale)); - - F32 max_scale = 0.f; - - BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); - - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; - - // compute position - LLVector3 position = LLVector3(0, 0, 0) * mat; - - // compute scale - LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; - LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; - LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; - F32 x_length = x_transformed.normalize(); - F32 y_length = y_transformed.normalize(); - F32 z_length = z_transformed.normalize(); - - max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); - - mat *= scale_mat; - - for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) - { //for each instance with said transform applied - LLModelInstance instance = *model_iter++; - - LLModel* base_model = instance.mModel; - - if (base_model && !requested_name.empty()) - { - base_model->mRequestedLabel = requested_name; - } - - for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) - { - LLModel* lod_model = NULL; - if (!legacyMatching) - { - // Fill LOD slots by finding matching meshes by label with name extensions - // in the appropriate scene for each LOD. This fixes all kinds of issues - // where the indexed method below fails in spectacular fashion. - // If you don't take the time to name your LOD and PHYS meshes - // with the name of their corresponding mesh in the HIGH LOD, - // then the indexed method will be attempted below. - - LLMatrix4 transform; - - std::string name_to_match = instance.mLabel; - llassert(!name_to_match.empty()); - - int extensionLOD; - if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty()) - { - extensionLOD = i; - } - else - { - //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for - extensionLOD = mPhysicsSearchLOD; - } - - std::string toAdd; - switch (extensionLOD) - { - case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; - case LLModel::LOD_LOW: toAdd = "_LOD1"; break; - case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; - case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } - - if (name_to_match.find(toAdd) == -1) - { - name_to_match += toAdd; - } - - FindModel(mScene[i], name_to_match, lod_model, transform); + loadModel(lod); +} - if (!lod_model && i != LLModel::LOD_PHYSICS) - { - 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); - } +//static +void LLFloaterModelPreview::onReset(void* user_data) +{ + assert_main_thread(); - int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; - while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) - { - std::string name_to_match = instance.mLabel; - llassert(!name_to_match.empty()); - - std::string toAdd; - switch (searchLOD) - { - case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; - case LLModel::LOD_LOW: toAdd = "_LOD1"; break; - case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; - case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } - - if (name_to_match.find(toAdd) == -1) - { - name_to_match += toAdd; - } - - // See if we can find an appropriately named model in LOD 'searchLOD' - // - FindModel(mScene[searchLOD], name_to_match, lod_model, transform); - searchLOD++; - } - } - } - else - { - // Use old method of index-based association - U32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { - // find reference instance for this model - if (mBaseModel[idx] == base_model) - { - if (mImporterDebug) - { - 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; - } - } - // If the model list for the current LOD includes that index... - // - if (mModel[i].size() > idx) - { - // Assign that index from the model list for our LOD as the LOD model for this instance - // - lod_model = mModel[i][idx]; - 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 (mImporterDebug) - { - std::ostringstream out; - out << "List of models does not include index " << idx; - LL_INFOS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - } - } + 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]; - if (lod_model) - { - if (mImporterDebug) - { - std::ostringstream out; - if (i == LLModel::LOD_PHYSICS) - { - out << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel; - } - else - { - 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; - } - else - { - if (i < LLModel::LOD_HIGH && !lodsReady()) - { - // assign a placeholder from previous LOD until lod generation is complete. - // 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 (mImporterDebug) - { - std::ostringstream out; - out << "List of models does not include " << instance.mLabel; - LL_INFOS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - } - } - } + fmp->resetDisplayOptions(); + fmp->resetUploadOptions(); + //reset model preview + fmp->initModelPreview(); - LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; - if (!high_lod_model) - { - setLoadState( LLModelLoader::ERROR_MATERIALS ); - mFMP->childDisable( "calculate_btn" ); - } - else - { - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - int refFaceCnt = 0; - int modelFaceCnt = 0; - llassert(instance.mLOD[i]); - if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) ) - { - setLoadState( LLModelLoader::ERROR_MATERIALS ); - mFMP->childDisable( "calculate_btn" ); - } - } - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; - bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean(); - if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0) - { - LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix); - LLQuaternion identity; - if (!bind_rot.isEqualEps(identity,0.01)) - { - 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 ); - } - } - } - instance.mTransform = mat; - mUploadData.push_back(instance); - } - } + mp = fmp->mModelPreview; + mp->loadModel(filename,LLModel::LOD_HIGH,true); +} - for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++) - { - // Search for models that are not included into upload data - // If we found any, that means something we loaded is not a sub-model. - for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind) - { - bool found_model = false; - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - if (instance.mLOD[lod] == mModel[lod][model_ind]) - { - found_model = true; - break; - } - } - if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) - { - 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" ); - } - } - } +//static +void LLFloaterModelPreview::onUpload(void* user_data) +{ + assert_main_thread(); - F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale; + LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; + mp->clearLogTab(); - F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); - max_axis = llmax(max_axis, mPreviewScale.mV[2]); - max_axis *= 2.f; + mp->mUploadBtn->setEnabled(false); - //clamp scale so that total imported model bounding box is smaller than 240m on a side - max_import_scale = llmin(max_import_scale, 240.f/max_axis); + mp->mModelPreview->rebuildUploadData(); - scale_spinner->setMaxValue(max_import_scale); + bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); + bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); + bool lock_scale_if_joint_position = mp->childGetValue("lock_scale_if_joint_position").asBoolean(); - if (max_import_scale < scale) + if (gSavedSettings.getBOOL("MeshImportUseSLM")) { - scale_spinner->setValue(max_import_scale); - } + mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions, lock_scale_if_joint_position); + } + gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, + mp->childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, + mp->mUploadModelUrl, + true, LLHandle<LLWholeModelFeeObserver>(), mp->getWholeModelUploadObserverHandle()); } -void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) -{ - if (!mLODFile[LLModel::LOD_HIGH].empty()) - { - std::string filename = mLODFile[LLModel::LOD_HIGH]; - std::string slm_filename; - - if (LLModelLoader::getSLMFilename(filename, slm_filename)) - { - saveUploadData(slm_filename, save_skinweights, save_joint_positions, lock_scale_if_joint_position); - } - } -} -void LLModelPreview::saveUploadData(const std::string& filename, - bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) -{ - - std::set<LLPointer<LLModel> > meshes; - std::map<LLModel*, std::string> mesh_binary; - - LLModel::hull empty_hull; - - LLSD data; - - data["version"] = SLM_SUPPORTED_VERSION; - if (!mBaseModel.empty()) - { - data["name"] = mBaseModel[0]->getName(); - } - - S32 mesh_id = 0; - - //build list of unique models and initialize local id - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (meshes.find(instance.mModel) == meshes.end()) - { - instance.mModel->mLocalID = mesh_id++; - meshes.insert(instance.mModel); - - std::stringstream str; - LLModel::Decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? - instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : - instance.mModel->mPhysics; - - LLModel::writeModel(str, - instance.mLOD[LLModel::LOD_PHYSICS], - instance.mLOD[LLModel::LOD_HIGH], - instance.mLOD[LLModel::LOD_MEDIUM], - instance.mLOD[LLModel::LOD_LOW], - instance.mLOD[LLModel::LOD_IMPOSTOR], - decomp, - save_skinweights, - save_joint_positions, - lock_scale_if_joint_position, - FALSE, TRUE, instance.mModel->mSubmodelID); - - data["mesh"][instance.mModel->mLocalID] = str.str(); - } - - data["instance"][i] = instance.asLLSD(); - } - - llofstream out(filename.c_str(), std::ios_base::out | std::ios_base::binary); - LLSDSerialize::toBinary(data, out); - out.flush(); - out.close(); -} - -void LLModelPreview::clearModel(S32 lod) -{ - if (lod < 0 || lod > LLModel::LOD_PHYSICS) - { - return; - } - - mVertexBuffer[lod].clear(); - mModel[lod].clear(); - mScene[lod].clear(); -} - -void LLModelPreview::getJointAliases( JointMap& joint_map) -{ - // Get all standard skeleton joints from the preview avatar. - LLVOAvatar *av = getPreviewAvatar(); - - //Joint names and aliases come from avatar_skeleton.xml - - joint_map = av->getJointAliases(); - - std::vector<std::string> cv_names, attach_names; - av->getSortedJointNames(1, cv_names); - av->getSortedJointNames(2, attach_names); - for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it) - { - joint_map[*it] = *it; - } - for (std::vector<std::string>::iterator it = attach_names.begin(); it != attach_names.end(); ++it) - { - joint_map[*it] = *it; - } -} - -void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm) -{ - assert_main_thread(); - - LLMutexLock lock(this); - - if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::NUM_LODS - 1) - { - 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; - } - - // This triggers if you bring up the file picker and then hit CANCEL. - // Just use the previous model (if any) and ignore that you brought up - // the file picker. - - if (filename.empty()) - { - if (mBaseModel.empty()) - { - // this is the initial file picking. Close the whole floater - // if we don't have a base model to show for high LOD. - mFMP->closeFloater(false); - } - mLoading = false; - return; - } - - if (mModelLoader) - { - LL_WARNS() << "Incompleted model load operation pending." << LL_ENDL; - return; - } - - mLODFile[lod] = filename; - - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } - - std::map<std::string, std::string> joint_alias_map; - getJointAliases(joint_alias_map); - - mModelLoader = new LLDAELoader( - filename, - lod, - &LLModelPreview::loadedCallback, - &LLModelPreview::lookupJointByName, - &LLModelPreview::loadTextures, - &LLModelPreview::stateChangedCallback, - this, - mJointTransformMap, - mJointsFromNode, - joint_alias_map, - LLSkinningUtil::getMaxJointCount(), - gSavedSettings.getU32("ImporterModelLimit"), - gSavedSettings.getBOOL("ImporterPreprocessDAE")); - - if (force_disable_slm) - { - mModelLoader->mTrySLM = false; - } - else - { - // For MAINT-6647, we have set force_disable_slm to true, - // which means this code path will never be taken. Trying to - // re-use SLM files has never worked properly; in particular, - // it tends to force the UI into strange checkbox options - // which cannot be altered. - - //only try to load from slm if viewer is configured to do so and this is the - //initial model load (not an LoD or physics shape) - mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); - } - mModelLoader->start(); - - mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); - - setPreviewLOD(lod); - - if ( getLoadState() >= LLModelLoader::ERROR_PARSING ) - { - mFMP->childDisable("ok_btn"); - mFMP->childDisable( "calculate_btn" ); - } - - if (lod == mPreviewLOD) - { - mFMP->childSetValue("lod_file_" + lod_name[lod], mLODFile[lod]); - } - else if (lod == LLModel::LOD_PHYSICS) - { - mFMP->childSetValue("physics_file", mLODFile[lod]); - } - - mFMP->openFloater(); -} - -void LLModelPreview::setPhysicsFromLOD(S32 lod) -{ - assert_main_thread(); - - if (lod >= 0 && lod <= 3) - { - mPhysicsSearchLOD = lod; - mModel[LLModel::LOD_PHYSICS] = mModel[lod]; - mScene[LLModel::LOD_PHYSICS] = mScene[lod]; - mLODFile[LLModel::LOD_PHYSICS].clear(); - mFMP->childSetValue("physics_file", mLODFile[LLModel::LOD_PHYSICS]); - mVertexBuffer[LLModel::LOD_PHYSICS].clear(); - rebuildUploadData(); - refresh(); - updateStatusMessages(); - } -} - -void LLModelPreview::clearIncompatible(S32 lod) -{ - //Don't discard models if specified model is the physic rep - if ( lod == LLModel::LOD_PHYSICS ) - { - return; - } - - // at this point we don't care about sub-models, - // different amount of sub-models means face count mismatch, not incompatibility - U32 lod_size = countRootModels(mModel[lod]); - for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model - if (i != lod) - { - if (countRootModels(mModel[i]) != lod_size) - { - mModel[i].clear(); - mScene[i].clear(); - mVertexBuffer[i].clear(); - - if (i == LLModel::LOD_HIGH) - { - mBaseModel = mModel[lod]; - clearGLODGroup(); - mBaseScene = mScene[lod]; - mVertexBuffer[5].clear(); - } - } - } - } -} - -void LLModelPreview::clearGLODGroup() -{ - if (mGroup) - { - for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - -void LLModelPreview::loadModelCallback(S32 loaded_lod) -{ - assert_main_thread(); - - LLMutexLock lock(this); - if (!mModelLoader) - { - mLoading = false ; - return; - } - if(getLoadState() >= LLModelLoader::ERROR_PARSING) - { - mLoading = false ; - mModelLoader = NULL; - mLodsWithParsingError.push_back(loaded_lod); - return ; - } - - mLodsWithParsingError.erase(std::remove(mLodsWithParsingError.begin(), mLodsWithParsingError.end(), loaded_lod), mLodsWithParsingError.end()); - if(mLodsWithParsingError.empty()) - { - mFMP->childEnable( "calculate_btn" ); - } - - // Copy determinations about rig so UI will reflect them - // - setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); - setLegacyRigFlags(mModelLoader->getLegacyRigFlags()); - - mModelLoader->loadTextures() ; - - if (loaded_lod == -1) - { //populate all LoDs from model loader scene - mBaseModel.clear(); - mBaseScene.clear(); - - bool skin_weights = false; - bool joint_overrides = false; - bool lock_scale_if_joint_position = false; - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { //for each LoD - - //clear scene and model info - mScene[lod].clear(); - mModel[lod].clear(); - mVertexBuffer[lod].clear(); - - if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) - { //if this LoD exists in the loaded scene - - //copy scene to current LoD - mScene[lod] = mModelLoader->mScene; - - //touch up copied scene to look like current LoD - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - LLModelLoader::model_instance_list& list = iter->second; - - for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) - { - //override displayed model with current LoD - list_iter->mModel = list_iter->mLOD[lod]; - - if (!list_iter->mModel) - { - continue; - } - - //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) - S32 idx = list_iter->mModel->mLocalID; - - if (mModel[lod].size() <= idx) - { //stretch model list to fit model at given index - mModel[lod].resize(idx+1); - } - - mModel[lod][idx] = list_iter->mModel; - if (!list_iter->mModel->mSkinWeights.empty()) - { - skin_weights = true; - - if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty()) - { - joint_overrides = true; - } - if (list_iter->mModel->mSkinInfo.mLockScaleIfJointPosition) - { - lock_scale_if_joint_position = true; - } - } - } - } - } - } - - if (mFMP) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; - - if (skin_weights) - { //enable uploading/previewing of skin weights if present in .slm file - fmp->enableViewOption("show_skin_weight"); - mViewOption["show_skin_weight"] = true; - fmp->childSetValue("upload_skin", true); - } - - 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) - { - fmp->enableViewOption("lock_scale_if_joint_position"); - mViewOption["lock_scale_if_joint_position"] = true; - fmp->childSetValue("lock_scale_if_joint_position", true); - } - } - - //copy high lod to base scene for LoD generation - mBaseScene = mScene[LLModel::LOD_HIGH]; - mBaseModel = mModel[LLModel::LOD_HIGH]; - - mDirty = true; - resetPreviewTarget(); - } - else - { //only replace given LoD - mModel[loaded_lod] = mModelLoader->mModelList; - mScene[loaded_lod] = mModelLoader->mScene; - mVertexBuffer[loaded_lod].clear(); - - setPreviewLOD(loaded_lod); - - if (loaded_lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation - if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD - mGenLOD = true; - } - - mBaseModel = mModel[loaded_lod]; - clearGLODGroup(); - - mBaseScene = mScene[loaded_lod]; - mVertexBuffer[5].clear(); - } - else - { - BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); - if (!legacyMatching) - { - if (!mBaseModel.empty()) - { - BOOL name_based = FALSE; - BOOL has_submodels = FALSE; - for (U32 idx = 0; idx < mBaseModel.size(); ++idx) - { - if (mBaseModel[idx]->mSubmodelID) - { // don't do index-based renaming when the base model has submodels - has_submodels = TRUE; - if (mImporterDebug) - { - std::ostringstream out; - out << "High LOD has submodels"; - LL_INFOS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - } - break; - } - } - - for (U32 idx = 0; idx < mModel[loaded_lod].size(); ++idx) - { - std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); - - LLModel* found_model = NULL; - LLMatrix4 transform; - FindModel(mBaseScene, loaded_name, found_model, transform); - if (found_model) - { // don't rename correctly named models (even if they are placed in a wrong order) - name_based = TRUE; - } - - if (mModel[loaded_lod][idx]->mSubmodelID) - { // don't rename the models when loaded LOD model has submodels - has_submodels = TRUE; - } - } - - if (mImporterDebug) - { - 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) - { // replace the name of the model loaded for any non-HIGH LOD to match the others (MAINT-5601) - // this actually works like "ImporterLegacyMatching" for this particular LOD - for (U32 idx = 0; idx < mModel[loaded_lod].size() && idx < mBaseModel.size(); ++idx) - { - std::string name = mBaseModel[idx]->mLabel; - std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); - - if (loaded_name != name) - { - switch (loaded_lod) - { - case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; - case LLModel::LOD_LOW: name += "_LOD1"; break; - case LLModel::LOD_MEDIUM: name += "_LOD2"; break; - case LLModel::LOD_PHYSICS: name += "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } - - if (mImporterDebug) - { - 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; - } - } - } - } - } - } - - clearIncompatible(loaded_lod); - - mDirty = true; - - if (loaded_lod == LLModel::LOD_HIGH) - { - resetPreviewTarget(); - } - } - - mLoading = false; - if (mFMP) - { - if (!mBaseModel.empty()) - { - const std::string& model_name = mBaseModel[0]->getName(); - LLLineEditor* description_form = mFMP->getChild<LLLineEditor>("description_form"); - if (description_form->getText().empty()) - { - 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(); - - mModelLoadedSignal(); - - mModelLoader = NULL; -} - -void LLModelPreview::resetPreviewTarget() -{ - if ( mModelLoader ) - { - mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; - mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; - } - - setPreviewTarget(mPreviewScale.magVec()*10.f); -} - -void LLModelPreview::generateNormals() -{ - assert_main_thread(); - - S32 which_lod = mPreviewLOD; - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); - - mRequestedCreaseAngle[which_lod] = angle_cutoff; - - angle_cutoff *= DEG_TO_RAD; - - if (which_lod == 3 && !mBaseModel.empty()) - { - if(mBaseModelFacesCopy.empty()) - { - mBaseModelFacesCopy.reserve(mBaseModel.size()); - for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) - { - v_LLVolumeFace_t faces; - (*it)->copyFacesTo(faces); - mBaseModelFacesCopy.push_back(faces); - } - } - - for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) - { - (*it)->generateNormals(angle_cutoff); - } - - mVertexBuffer[5].clear(); - } - - bool perform_copy = mModelFacesCopy[which_lod].empty(); - if(perform_copy) { - mModelFacesCopy[which_lod].reserve(mModel[which_lod].size()); - } - - for (LLModelLoader::model_list::iterator it = mModel[which_lod].begin(), itE = mModel[which_lod].end(); it != itE; ++it) - { - if(perform_copy) - { - v_LLVolumeFace_t faces; - (*it)->copyFacesTo(faces); - mModelFacesCopy[which_lod].push_back(faces); - } - - (*it)->generateNormals(angle_cutoff); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - updateStatusMessages(); -} - -void LLModelPreview::restoreNormals() -{ - S32 which_lod = mPreviewLOD; - - if (which_lod > 4 || which_lod < 0 || - mModel[which_lod].empty()) - { - return; - } - - if(!mBaseModelFacesCopy.empty()) - { - llassert(mBaseModelFacesCopy.size() == mBaseModel.size()); - - vv_LLVolumeFace_t::const_iterator itF = mBaseModelFacesCopy.begin(); - for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it, ++itF) - { - (*it)->copyFacesFrom((*itF)); - } - - mBaseModelFacesCopy.clear(); - } - - if(!mModelFacesCopy[which_lod].empty()) - { - vv_LLVolumeFace_t::const_iterator itF = mModelFacesCopy[which_lod].begin(); - for (LLModelLoader::model_list::iterator it = mModel[which_lod].begin(), itE = mModel[which_lod].end(); it != itE; ++it, ++itF) - { - (*it)->copyFacesFrom((*itF)); - } - - mModelFacesCopy[which_lod].clear(); - } - - mVertexBuffer[which_lod].clear(); - refresh(); - updateStatusMessages(); -} - -void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) -{ - // Allow LoD from -1 to LLModel::LOD_PHYSICS - if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) - { - 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; - } - - if (mBaseModel.empty()) - { - return; - } - - LLVertexBuffer::unbind(); - - bool no_ff = LLGLSLShader::sNoFixedFunction; - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - LLGLSLShader::sNoFixedFunction = false; - - if (shader) - { - shader->unbind(); - } - - stop_gloderror(); - static U32 cur_name = 1; - - S32 limit = -1; - - U32 triangle_count = 0; - - U32 instanced_triangle_count = 0; - - //get the triangle count for the whole scene - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) - { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) - { - LLModel* mdl = instance->mModel; - if (mdl) - { - instanced_triangle_count += mdl->getNumTriangles(); - } - } - } - - //get the triangle count for the non-instanced set of models - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - triangle_count += mBaseModel[i]->getNumTriangles(); - } - - //get ratio of uninstanced triangles to instanced triangles - F32 triangle_ratio = (F32) triangle_count / (F32) instanced_triangle_count; - - U32 base_triangle_count = triangle_count; - - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - U32 lod_mode = 0; - - F32 lod_error_threshold = 0; - - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) - { - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); - if (iface) - { - lod_mode = iface->getFirstSelectedIndex(); - } - - lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); - } - - if (which_lod != -1) - { - mRequestedLoDMode[which_lod] = lod_mode; - } - - if (lod_mode == 0) - { - lod_mode = GLOD_TRIANGLE_BUDGET; - - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) - { - limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); - //convert from "scene wide" to "non-instanced" triangle limit - limit = (S32) ( (F32) limit*triangle_ratio ); - } - } - else - { - lod_mode = GLOD_ERROR_THRESHOLD; - } - - bool object_dirty = false; - - if (mGroup == 0) - { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); - } - - if (object_dirty) - { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; - - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } - - mObject[mdl] = cur_name++; - - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); - - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } - - if (mVertexBuffer[5].empty()) - { - genBuffers(5, false); - } - - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) - { - LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; - buff->setBuffer(type_mask & buff->getTypeMask()); - - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*) mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices/3; - stop_gloderror(); - } - - glodBuildObject(mObject[mdl]); - stop_gloderror(); - } - } - - - S32 start = LLModel::LOD_HIGH; - S32 end = 0; - - if (which_lod != -1) - { - start = end = which_lod; - } - - mMaxTriangleLimit = base_triangle_count; - - for (S32 lod = start; lod >= end; --lod) - { - if (which_lod == -1) - { - if (lod < start) - { - triangle_count /= decimation; - } - } - else - { - if (enforce_tri_limit) - { - triangle_count = limit; - } - else - { - for (S32 j=LLModel::LOD_HIGH; j>which_lod; --j) - { - triangle_count /= decimation; - } - } - } - - mModel[lod].clear(); - mModel[lod].resize(mBaseModel.size()); - mVertexBuffer[lod].clear(); - - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - mRequestedTriangleCount[lod] = (S32) ( (F32) triangle_count / triangle_ratio ); - mRequestedErrorThreshold[lod] = lod_error_threshold; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - if (lod_mode != GLOD_TRIANGLE_BUDGET) - { - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); - } - else - { - //SH-632: always add 1 to desired amount to avoid decimating below desired amount - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count+1); - } - - stop_gloderror(); - glodAdaptGroup(mGroup); - stop_gloderror(); - - for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) - { - LLModel* base = mBaseModel[mdl_idx]; - - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - - std::string name = base->mLabel; - - switch (lod) - { - case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; - case LLModel::LOD_LOW: name += "_LOD1"; break; - case LLModel::LOD_MEDIUM: name += "_LOD2"; break; - case LLModel::LOD_PHYSICS: name += "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } - - mModel[lod][mdl_idx]->mLabel = name; - mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; - - GLint* sizes = new GLint[patch_count*2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); - - LLModel* target_model = mModel[lod][mdl_idx]; - - for (GLint i = 0; i < patch_count; ++i) - { - type_mask = mVertexBuffer[5][base][i]->getTypeMask(); - - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); - - if (sizes[i*2+1] > 0 && sizes[i*2] > 0) - { - if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true)) - { - // Todo: find a way to stop preview in this case instead of crashing - LL_ERRS() << "Failed buffer allocation during preview LOD generation." - << " Vertices: " << sizes[i * 2 + 1] - << " Indices: " << sizes[i * 2] << LL_ENDL; - } - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*) buff->getIndicesPointer()); - stop_gloderror(); - } - else - { - // This face was eliminated or we failed to allocate buffer, - // attempt to create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset((U8*) buff->getMappedData(), 0, buff->getSize()); - memset((U8*) buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } - - buff->validateRange(0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - - LLStrider<LLVector3> pos; - LLStrider<LLVector3> norm; - LLStrider<LLVector2> tc; - LLStrider<U16> index; - - buff->getVertexStrider(pos); - if (type_mask & LLVertexBuffer::MAP_NORMAL) - { - buff->getNormalStrider(norm); - } - if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) - { - buff->getTexCoord0Strider(tc); - } - - buff->getIndexStrider(index); - - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices()/3; - actual_verts += buff->getNumVerts(); - ++submeshes; - - if (!validate_face(target_model->getVolumeFace(names[i]))) - { - LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; - } - } - - //blind copy skin weights and just take closest skin weight to point on - //decimated mesh for now (auto-generating LODs with skin weights is still a bit - //of an open problem). - target_model->mPosition = base->mPosition; - target_model->mSkinWeights = base->mSkinWeights; - target_model->mSkinInfo = base->mSkinInfo; - //copy material list - target_model->mMaterialList = base->mMaterialList; - - if (!validate_model(target_model)) - { - LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; - } - - delete [] sizes; - delete [] names; - } - - //rebuild scene based on mBaseScene - mScene[lod].clear(); - mScene[lod] = mBaseScene; - - for (U32 i = 0; i < mBaseModel.size(); ++i) - { - LLModel* mdl = mBaseModel[i]; - LLModel* target = mModel[lod][i]; - if (target) - { - for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) - { - for (U32 j = 0; j < iter->second.size(); ++j) - { - if (iter->second[j].mModel == mdl) - { - iter->second[j].mModel = target; - } - } - } - } - } - } - - mResourceCost = calcResourceCost(); - - LLVertexBuffer::unbind(); - LLGLSLShader::sNoFixedFunction = no_ff; - if (shader) - { - shader->bind(); - } -} - -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]; - std::vector<S32> submeshes[LLModel::NUM_LODS]; - - //total triangle/vertex/submesh count for each lod - S32 total_tris[LLModel::NUM_LODS]; - S32 total_verts[LLModel::NUM_LODS]; - S32 total_submeshes[LLModel::NUM_LODS]; - - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - total_tris[i] = 0; - total_verts[i] = 0; - total_submeshes[i] = 0; - } - - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH]; - if (!model_high_lod) - { - setLoadState( LLModelLoader::ERROR_MATERIALS ); - mFMP->childDisable( "calculate_btn" ); - continue; - } - - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - LLModel* lod_model = instance.mLOD[i]; - if (!lod_model) - { - setLoadState( LLModelLoader::ERROR_MATERIALS ); - mFMP->childDisable( "calculate_btn" ); - } - else - { - //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = lod_model->getNumVolumeFaces(); - - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = lod_model->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; - } - - std::string instance_name = instance.mLabel; - - 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. - // - 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()) - { - out << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter); - LL_INFOS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - out.str(""); - mat_iter++; - } - } - - //add this model to the lod total - total_tris[i] += cur_tris; - total_verts[i] += cur_verts; - total_submeshes[i] += cur_submeshes; - - //store this model's counts to asset data - tris[i].push_back(cur_tris); - verts[i].push_back(cur_verts); - submeshes[i].push_back(cur_submeshes); - } - } - } - - if (mMaxTriangleLimit == 0) - { - mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; - } - - 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() && !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 && !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) && !mHasDegenerate; ) - { - U16 index_a = face.mIndices[k + 0]; - U16 index_b = face.mIndices[k + 1]; - U16 index_c = face.mIndices[k + 2]; - - 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 - { - LL_DEBUGS("MeshValidation") << "Empty placeholder triangle (3 identical index 0 verts) ignored" << LL_ENDL; - } - else - { - 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"); - - S32 upload_status[LLModel::LOD_HIGH+1]; - - mModelNoErrors = true; - - const U32 lod_high = LLModel::LOD_HIGH; - U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]); - - for (S32 lod = 0; lod <= lod_high; ++lod) - { - upload_status[lod] = 0; - - std::string message = "mesh_status_good"; - - if (total_tris[lod] > 0) - { - mFMP->childSetValue(lod_triangles_name[lod], llformat("%d", total_tris[lod])); - mFMP->childSetValue(lod_vertices_name[lod], llformat("%d", total_verts[lod])); - } - else - { - if (lod == lod_high) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - else - { - for (S32 i = lod-1; i >= 0; --i) - { - if (total_tris[i] > 0) - { - upload_status[lod] = 2; - message = "mesh_status_missing_lod"; - } - } - } - - mFMP->childSetValue(lod_triangles_name[lod], mesh_status_na); - mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na); - } - - if (lod != lod_high) - { - if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) - { //number of submeshes is different - message = "mesh_status_submesh_mismatch"; - upload_status[lod] = 2; - } - else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count) - {//number of submodels is different, not all faces are matched correctly. - message = "mesh_status_submesh_mismatch"; - upload_status[lod] = 2; - // Note: Submodels in instance were loaded from higher LOD and as result face count - // returns same value and total_submeshes[lod] is identical to high_lod one. - } - else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) - { //number of meshes is different - message = "mesh_status_mesh_mismatch"; - upload_status[lod] = 2; - } - else if (!verts[lod].empty()) - { - S32 sum_verts_higher_lod = 0; - S32 sum_verts_this_lod = 0; - for (U32 i = 0; i < verts[lod].size(); ++i) - { - sum_verts_higher_lod += ((i < verts[lod+1].size()) ? verts[lod+1][i] : 0); - sum_verts_this_lod += verts[lod][i]; - } - - if ((sum_verts_higher_lod > 0) && - (sum_verts_this_lod > sum_verts_higher_lod)) - { - //too many vertices in this lod - message = "mesh_status_too_many_vertices"; - upload_status[lod] = 1; - } - } - } - - LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]); - LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); - icon->setVisible(true); - icon->setImage(img); - - if (upload_status[lod] >= 2) - { - mModelNoErrors = false; - } - - if (lod == mPreviewLOD) - { - mFMP->childSetValue("lod_status_message_text", mFMP->getString(message)); - icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon"); - icon->setImage(img); - } - - updateLodControls(lod); - } - - - //warn if hulls have more than 256 points in them - BOOL physExceededVertexLimit = FALSE; - for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; - - if (mdl) - { - for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) - { - if (mdl->mPhysics.mHull[j].size() > 256) - { - physExceededVertexLimit = TRUE; - LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; - break; - } - } - } - } - - if (physExceededVertexLimit) - { - 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) - { - mModelNoErrors = false; - LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; - } - - bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); - bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); - - if ( uploadingSkin ) - { - if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) - { - mModelNoErrors = false; - LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; - } - } - - if(mModelNoErrors && mModelLoader) - { - if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) - { - // Some textures are still loading, prevent upload until they are done - mModelNoErrors = false; - } - } - - if (!mModelNoErrors || mHasDegenerate) - { - mFMP->childDisable("ok_btn"); - mFMP->childDisable("calculate_btn"); - } - else - { - mFMP->childEnable("ok_btn"); - mFMP->childEnable("calculate_btn"); - } - - if (mModelNoErrors && mLodsWithParsingError.empty()) - { - mFMP->childEnable("calculate_btn"); - } - else - { - mFMP->childDisable("calculate_btn"); - } - - //add up physics triangles etc - S32 phys_tris = 0; - S32 phys_hulls = 0; - S32 phys_points = 0; - - //get the triangle count for the whole scene - for (LLModelLoader::scene::iterator iter = mScene[LLModel::LOD_PHYSICS].begin(), endIter = mScene[LLModel::LOD_PHYSICS].end(); iter != endIter; ++iter) - { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) - { - LLModel* model = instance->mModel; - if (model) - { - S32 cur_submeshes = model->getNumVolumeFaces(); - - LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull; - - if (!decomp.empty()) - { - phys_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) - { - phys_points += decomp[i].size(); - } - } - else - { //choose physics shape OR decomposition, can't use both - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = model->getVolumeFace(j); - phys_tris += face.mNumIndices/3; - } - } - } - } - } - - if (phys_tris > 0) - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); - } - else - { - mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); - } - - if (phys_hulls > 0) - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); - mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); - } - else - { - mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); - mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp) - { - if (phys_tris > 0 || phys_hulls > 0) - { - if (!fmp->isViewOptionEnabled("show_physics")) - { - fmp->enableViewOption("show_physics"); - mViewOption["show_physics"] = true; - fmp->childSetValue("show_physics", true); - } - } - else - { - fmp->disableViewOption("show_physics"); - mViewOption["show_physics"] = false; - fmp->childSetValue("show_physics", false); - - } - - //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); - - //fmp->childSetEnabled("physics_optimize", !use_hull); - - bool enable = (phys_tris > 0 || phys_hulls > 0) && fmp->mCurRequest.empty(); - //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); - - //enable/disable "analysis" UI - LLPanel* panel = fmp->getChild<LLPanel>("physics analysis"); - LLView* child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - enable = phys_hulls > 0 && fmp->mCurRequest.empty(); - //enable/disable "simplification" UI - panel = fmp->getChild<LLPanel>("physics simplification"); - child = panel->getFirstChild(); - while (child) - { - child->setEnabled(enable); - child = panel->findNextSibling(child); - } - - if (fmp->mCurRequest.empty()) - { - fmp->childSetVisible("Simplify", true); - fmp->childSetVisible("simplify_cancel", false); - fmp->childSetVisible("Decompose", true); - fmp->childSetVisible("decompose_cancel", false); - - if (phys_hulls > 0) - { - fmp->childEnable("Simplify"); - } - - if (phys_tris || phys_hulls > 0) - { - fmp->childEnable("Decompose"); - } - } - else - { - fmp->childEnable("simplify_cancel"); - fmp->childEnable("decompose_cancel"); - } - } - - - LLCtrlSelectionInterface* iface = fmp->childGetSelectionInterface("physics_lod_combo"); - S32 which_mode = 0; - S32 file_mode = 1; - if (iface) - { - which_mode = iface->getFirstSelectedIndex(); - file_mode = iface->getItemCount() - 1; - } - - if (which_mode == file_mode) - { - mFMP->childEnable("physics_file"); - mFMP->childEnable("physics_browse"); - } - else - { - mFMP->childDisable("physics_file"); - mFMP->childDisable("physics_browse"); - } - - LLSpinCtrl* crease = mFMP->getChild<LLSpinCtrl>("crease_angle"); - - if (mRequestedCreaseAngle[mPreviewLOD] == -1.f) - { - mFMP->childSetColor("crease_label", LLColor4::grey); - crease->forceSetValue(75.f); - } - else - { - mFMP->childSetColor("crease_label", LLColor4::white); - crease->forceSetValue(mRequestedCreaseAngle[mPreviewLOD]); - } - - mModelUpdatedSignal(true); - -} - -void LLModelPreview::updateLodControls(S32 lod) -{ - if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::LOD_HIGH) - { - 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; - } - - const char* lod_controls[] = - { - "lod_mode_", - "lod_triangle_limit_", - "lod_error_threshold_" - }; - const U32 num_lod_controls = sizeof(lod_controls)/sizeof(char*); - - const char* file_controls[] = - { - "lod_browse_", - "lod_file_", - }; - const U32 num_file_controls = sizeof(file_controls)/sizeof(char*); - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (!fmp) return; - - LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[lod]); - if (!lod_combo) return; - - S32 lod_mode = lod_combo->getCurrentIndex(); - if (lod_mode == LOD_FROM_FILE) // LoD from file - { - fmp->mLODMode[lod] = 0; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childSetVisible(file_controls[i] + lod_name[lod], true); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); - } - } - else if (lod_mode == USE_LOD_ABOVE) // use LoD above - { - fmp->mLODMode[lod] = 2; - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->childSetVisible(file_controls[i] + lod_name[lod], false); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); - } - - if (lod < LLModel::LOD_HIGH) - { - mModel[lod] = mModel[lod + 1]; - mScene[lod] = mScene[lod + 1]; - mVertexBuffer[lod].clear(); - - // Also update lower LoD - if (lod > LLModel::LOD_IMPOSTOR) - { - updateLodControls(lod - 1); - } - } - } - else // auto generate, the default case for all LoDs except High - { - fmp->mLODMode[lod] = 1; - - //don't actually regenerate lod when refreshing UI - mLODFrozen = true; - - for (U32 i = 0; i < num_file_controls; ++i) - { - mFMP->getChildView(file_controls[i] + lod_name[lod])->setVisible(false); - } - - for (U32 i = 0; i < num_lod_controls; ++i) - { - mFMP->getChildView(lod_controls[i] + lod_name[lod])->setVisible(true); - } - - - LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold_" + lod_name[lod]); - LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod]); - - limit->setMaxValue(mMaxTriangleLimit); - limit->forceSetValue(mRequestedTriangleCount[lod]); - - threshold->forceSetValue(mRequestedErrorThreshold[lod]); - - mFMP->getChild<LLComboBox>("lod_mode_" + lod_name[lod])->selectNthItem(mRequestedLoDMode[lod]); - - if (mRequestedLoDMode[lod] == 0) - { - limit->setVisible(true); - threshold->setVisible(false); - - limit->setMaxValue(mMaxTriangleLimit); - limit->setIncrement(mMaxTriangleLimit/32); - } - else - { - limit->setVisible(false); - threshold->setVisible(true); - } - - mLODFrozen = false; - } -} - -void LLModelPreview::setPreviewTarget(F32 distance) -{ - mCameraDistance = distance; - mCameraZoom = 1.f; - mCameraPitch = 0.f; - mCameraYaw = 0.f; - mCameraOffset.clearVec(); -} - -void LLModelPreview::clearBuffers() -{ - for (U32 i = 0; i < 6; i++) - { - mVertexBuffer[i].clear(); - } -} - -void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) -{ - U32 tri_count = 0; - U32 vertex_count = 0; - U32 mesh_count = 0; - - - LLModelLoader::model_list* model = NULL; - - if (lod < 0 || lod > 4) - { - model = &mBaseModel; - lod = 5; - } - else - { - model = &(mModel[lod]); - } - - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - - mVertexBuffer[lod].clear(); - - LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); - - for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) - { - LLModel* mdl = *iter; - if (!mdl) - { - continue; - } - - LLModel* base_mdl = *base_iter; - base_iter++; - - S32 num_faces = mdl->getNumVolumeFaces(); - for (S32 i = 0; i < num_faces; ++i) - { - const LLVolumeFace &vf = mdl->getVolumeFace(i); - U32 num_vertices = vf.mNumVertices; - U32 num_indices = vf.mNumIndices; - - if (!num_vertices || ! num_indices) - { - continue; - } - - LLVertexBuffer* vb = NULL; - - bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); - - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 ; - - if (skinned) - { - mask |= LLVertexBuffer::MAP_WEIGHT4; - } - - vb = new LLVertexBuffer(mask, 0); - - 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 - 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; - LLStrider<LLVector3> normal_strider; - LLStrider<LLVector2> tc_strider; - LLStrider<U16> index_strider; - LLStrider<LLVector4> weights_strider; - - vb->getVertexStrider(vertex_strider); - vb->getIndexStrider(index_strider); - - if (skinned) - { - vb->getWeight4Strider(weights_strider); - } - - LLVector4a::memcpyNonAliased16((F32*) vertex_strider.get(), (F32*) vf.mPositions, num_vertices*4*sizeof(F32)); - - if (vf.mTexCoords) - { - vb->getTexCoord0Strider(tc_strider); - S32 tex_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*) tc_strider.get(), (F32*) vf.mTexCoords, tex_size); - } - - if (vf.mNormals) - { - vb->getNormalStrider(normal_strider); - LLVector4a::memcpyNonAliased16((F32*) normal_strider.get(), (F32*) vf.mNormals, num_vertices*4*sizeof(F32)); - } - - if (skinned) - { - for (U32 i = 0; i < num_vertices; i++) - { - //find closest weight to vf.mVertices[i].mPosition - LLVector3 pos(vf.mPositions[i].getF32ptr()); - - const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); - llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this - - LLVector4 w(0,0,0,0); - - for (U32 i = 0; i < weight_list.size(); ++i) - { - F32 wght = llclamp(weight_list[i].mWeight, 0.001f, 0.999f); - F32 joint = (F32) weight_list[i].mJointIdx; - w.mV[i] = joint + wght; - llassert(w.mV[i]-(S32)w.mV[i]>0.0f); // because weights are non-zero, and range of wt values - //should not cause floating point precision issues. - } - - *(weights_strider++) = w; - } - } - - // build indices - for (U32 i = 0; i < num_indices; i++) - { - *(index_strider++) = vf.mIndices[i]; - } - - mVertexBuffer[lod][mdl].push_back(vb); - - vertex_count += num_vertices; - tri_count += num_indices/3; - ++mesh_count; - - } - } -} - -void LLModelPreview::update() -{ - if (mGenLOD) - { - bool subscribe_for_generation = mLodsQuery.empty(); - mGenLOD = false; - mDirty = true; - mLodsQuery.clear(); - - for (S32 lod = LLModel::LOD_HIGH; lod >= 0; --lod) - { - // adding all lods into query for generation - mLodsQuery.push_back(lod); - } - - if (subscribe_for_generation) - { - doOnIdleRepeating(lodQueryCallback); - } - } - - if (mDirty && mLodsQuery.empty()) - { - mDirty = false; - mResourceCost = calcResourceCost(); - refresh(); - updateStatusMessages(); - } -} - -//----------------------------------------------------------------------------- -// createPreviewAvatar -//----------------------------------------------------------------------------- -void LLModelPreview::createPreviewAvatar( void ) -{ - mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR ); - if ( mPreviewAvatar ) - { - mPreviewAvatar->createDrawable( &gPipeline ); - mPreviewAvatar->mSpecialRenderMode = 1; - mPreviewAvatar->startMotion( ANIM_AGENT_STAND ); - mPreviewAvatar->hideSkirt(); - } - else - { - LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; - } -} - -//static -U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) -{ - U32 root_models = 0; - model_list::iterator model_iter = models.begin(); - while (model_iter != models.end()) - { - LLModel* mdl = *model_iter; - if (mdl && mdl->mSubmodelID == 0) - { - root_models++; - } - model_iter++; - } - return root_models; -} - -void LLModelPreview::loadedCallback( - LLModelLoader::scene& scene, - LLModelLoader::model_list& model_list, - S32 lod, - void* opaque) -{ - LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); - if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) - { - // 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) -{ - LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); - if (pPreview) - { - pPreview->setLoadState(state); - } -} - -LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) -{ - LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); - if (pPreview) - { - return pPreview->getPreviewAvatar()->getJoint(str); - } - return NULL; -} - -U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque) -{ - (void)opaque; - - if (material.mDiffuseMapFilename.size()) - { - material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; - LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); - - tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); - tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); - tex->forceToSaveRawImage(0, F32_MAX); - material.setDiffuseMap(tex->getID()); // record tex ID - return 1; - } - - material.mOpaqueData = NULL; - return 0; -} - -void LLModelPreview::addEmptyFace( LLModel* pTarget ) -{ - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); - - buff->allocateBuffer(1, 3, true); - memset( (U8*) buff->getMappedData(), 0, buff->getSize() ); - memset( (U8*) buff->getIndicesPointer(), 0, buff->getIndicesSize() ); - - buff->validateRange( 0, buff->getNumVerts()-1, buff->getNumIndices(), 0 ); - - LLStrider<LLVector3> pos; - LLStrider<LLVector3> norm; - LLStrider<LLVector2> tc; - LLStrider<U16> index; - - buff->getVertexStrider(pos); - - if ( type_mask & LLVertexBuffer::MAP_NORMAL ) - { - buff->getNormalStrider(norm); - } - if ( type_mask & LLVertexBuffer::MAP_TEXCOORD0 ) - { - buff->getTexCoord0Strider(tc); - } - - buff->getIndexStrider(index); - - //resize face array - int faceCnt = pTarget->getNumVolumeFaces(); - 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(); - - LLMutexLock lock(this); - mNeedsUpdate = FALSE; - - bool use_shaders = LLGLSLShader::sNoFixedFunction; - - bool edges = mViewOption["show_edges"]; - bool joint_overrides = mViewOption["show_joint_overrides"]; - bool joint_positions = mViewOption["show_joint_positions"]; - bool skin_weight = mViewOption["show_skin_weight"]; - bool textures = mViewOption["show_textures"]; - bool physics = mViewOption["show_physics"]; - - // Extra configurability, to be exposed later as controls? - static LLCachedControl<LLColor4> canvas_col(gSavedSettings, "MeshPreviewCanvasColor"); - static LLCachedControl<LLColor4> edge_col(gSavedSettings, "MeshPreviewEdgeColor"); - static LLCachedControl<LLColor4> base_col(gSavedSettings, "MeshPreviewBaseColor"); - static LLCachedControl<LLColor3> brightness(gSavedSettings, "MeshPreviewBrightnessColor"); - static LLCachedControl<F32> edge_width(gSavedSettings, "MeshPreviewEdgeWidth"); - static LLCachedControl<LLColor4> phys_edge_col(gSavedSettings, "MeshPreviewPhysicsEdgeColor"); - static LLCachedControl<LLColor4> phys_fill_col(gSavedSettings, "MeshPreviewPhysicsFillColor"); - static LLCachedControl<F32> phys_edge_width(gSavedSettings, "MeshPreviewPhysicsEdgeWidth"); - static LLCachedControl<LLColor4> deg_edge_col(gSavedSettings, "MeshPreviewDegenerateEdgeColor"); - static LLCachedControl<LLColor4> deg_fill_col(gSavedSettings, "MeshPreviewDegenerateFillColor"); - static LLCachedControl<F32> deg_edge_width(gSavedSettings, "MeshPreviewDegenerateEdgeWidth"); - static LLCachedControl<F32> deg_point_size(gSavedSettings, "MeshPreviewDegeneratePointSize"); - - S32 width = getWidth(); - S32 height = getHeight(); - - LLGLSUIDefault def; // GL_BLEND, GL_ALPHA_TEST, GL_CULL_FACE, depth test - LLGLDisable no_blend(GL_BLEND); - LLGLDepthTest depth(GL_FALSE); // SL-12781 disable z-buffer to render background color - LLGLDisable fog(GL_FOG); - - { - if (use_shaders) - { - gUIProgram.bind(); - } - //clear background to grey - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); - - gGL.color4fv(static_cast<LLColor4>(canvas_col).mV); - gl_rect_2d_simple( width, height ); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - if (use_shaders) - { - gUIProgram.unbind(); - } - } - - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - - bool has_skin_weights = false; - bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); - bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); - - if ( upload_joints != mLastJointUpdate ) - { - mLastJointUpdate = upload_joints; - } - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].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; - model->mPelvisOffset = mPelvisZOffset; - if (!model->mSkinWeights.empty()) - { - has_skin_weights = true; - } - } - } - - if (has_skin_weights && lodsReady()) - { //model has skin weights, enable view options for skin weights and joint positions - 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 - { - mFMP->childDisable("upload_skin"); - if (fmp) - { - mViewOption["show_skin_weight"] = false; - fmp->disableViewOption("show_skin_weight"); - fmp->disableViewOption("show_joint_overrides"); - fmp->disableViewOption("show_joint_positions"); - - skin_weight = false; - mFMP->childSetValue("show_skin_weight", false); - fmp->setViewOptionEnabled("show_skin_weight", skin_weight); - } - } - - if (upload_skin && !has_skin_weights) - { //can't upload skin weights if model has no skin weights - mFMP->childSetValue("upload_skin", false); - upload_skin = false; - } - - if (!upload_skin && upload_joints) - { //can't upload joints if not uploading skin weights - mFMP->childSetValue("upload_joints", false); - upload_joints = false; - } - - 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 - if ( isRigValidForJointPositionUpload() ) - { - mFMP->childSetEnabled("upload_joints", upload_skin); - } - - F32 explode = mFMP->childGetValue("physics_explode").asReal(); - - LLGLDepthTest gls_depth(GL_TRUE); // SL-12781 re-enable z-buffer for 3D model preview - - LLRect preview_rect; - - preview_rect = mFMP->getChildView("preview_panel")->getRect(); - - F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); - - LLViewerCamera::getInstance()->setAspect(aspect); - - LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - - LLVector3 offset = mCameraOffset; - LLVector3 target_pos = mPreviewTarget+offset; - - F32 z_near = 0.001f; - F32 z_far = mCameraDistance*10.0f+mPreviewScale.magVec()+mCameraOffset.magVec(); - - if (skin_weight) - { - target_pos = getPreviewAvatar()->getPositionAgent() + offset; - z_near = 0.01f; - z_far = 1024.f; - - //render avatar previews every frame - refresh(); - } - - if (use_shaders) - { - gObjectPreviewProgram.bind(); - } - - gGL.loadIdentity(); - gPipeline.enableLightsPreview(); - - LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * - 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(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - - z_near = llclamp(z_far * 0.001f, 0.001f, 0.1f); - - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); - - stop_glerror(); - - gGL.pushMatrix(); - gGL.color4fv(edge_col().mV); - - const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - - LLGLEnable normalize(GL_NORMALIZE); - - if (!mBaseModel.empty() && mVertexBuffer[5].empty()) - { - genBuffers(-1, skin_weight); - //genBuffers(3); - //genLODs(); - } - - if (!mModel[mPreviewLOD].empty()) - { - mFMP->childEnable("reset_btn"); - - bool regen = mVertexBuffer[mPreviewLOD].empty(); - if (!regen) - { - const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; - if (!vb_vec.empty()) - { - const LLVertexBuffer* buff = vb_vec[0]; - regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; - } - else - { - LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; - regen = TRUE; - } - } - - if (regen) - { - genBuffers(mPreviewLOD, skin_weight); - } - - if (!skin_weight) - { - for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[mPreviewLOD]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*) mat.mMatrix); - - - U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); - for (U32 i = 0; i < num_models; ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - - if (textures) - { - int materialCnt = instance.mModel->mMaterialList.size(); - if ( i < materialCnt ) - { - const std::string& binding = instance.mModel->mMaterialList[i]; - const LLImportMaterial& material = instance.mMaterial[binding]; - - gGL.diffuseColor4fv(material.mDiffuseColor.mV); - - // Find the tex for this material, bind it, and add it to our set - // - LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); - if (tex) - { - mTextureSet.insert(tex); - } - } - } - else - { - 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.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV); - if (edges) - { - 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); - glLineWidth(1.f); - } - } - gGL.popMatrix(); - } - - if (physics) - { - glClear(GL_DEPTH_BUFFER_BIT); - - for (U32 pass = 0; pass < 2; pass++) - { - if (pass == 0) - { //depth only pass - gGL.setColorMask(false, false); - } - else - { - gGL.setColorMask(true, true); - } - - //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) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*)mat.mMatrix); - - - bool render_mesh = true; - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - LLModel::Decomposition& physics = model->mPhysics; - - if (!physics.mHull.empty()) - { - render_mesh = false; - - if (physics.mMesh.empty()) - { //build vertex buffer for physics mesh - gMeshRepo.buildPhysicsMesh(physics); - } - - if (!physics.mMesh.empty()) - { //render hull instead of mesh - for (U32 i = 0; i < physics.mMesh.size(); ++i) - { - if (explode > 0.f) - { - gGL.pushMatrix(); - - LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters; - offset *= explode; - - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - } - - 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)); - } - - 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 (render_mesh) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - - 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.diffuseColor4fv(phys_fill_col().mV); - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); - - 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); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); - } - } - } - gGL.popMatrix(); - } - - // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] - if (pass > 0 && mHasDegenerate) - { - 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) - { - LLModelInstance& instance = *iter; - - LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; - - if (!model) - { - continue; - } - - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*)mat.mMatrix); - - - LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; - if (decomp) - { - LLMutexLock(decomp->mMutex); - - LLModel::Decomposition& physics = model->mPhysics; - - if (physics.mHull.empty()) - { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - - U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); - for (U32 v = 0; v < num_models; ++v) - { - 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); - - LLVector4a v1, v2, v3; - for (U32 indices_offset = 0; indices_offset < buffer->getNumIndices(); indices_offset += 3) - { - v1.setMul(pos[*idx++], scale); - v2.setMul(pos[*idx++], scale); - v3.setMul(pos[*idx++], scale); - - if (ll_is_degenerate(v1, v2, v3)) - { - 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(); - } - 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(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest - - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].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; - - 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]; - - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider<LLVector3> position; - buffer->getVertexStrider(position); - - LLStrider<LLVector4> weight; - buffer->getWeight4Strider(weight); - - //quick 'n dirty software vertex skinning - - //build matrix palette - - LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, - skin, getPreviewAvatar()); - - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); - U32 max_joints = LLSkinningUtil::getMaxJointCount(); - for (U32 j = 0; j < buffer->getNumVerts(); ++j) - { - LLMatrix4a final_mat; - F32 *wptr = weight[j].mV; - LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); - - //VECTORIZE THIS - LLVector4a& v = face.mPositions[j]; - - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - - position[j][0] = dst[0]; - position[j][1] = dst[1]; - position[j][2] = dst[2]; - } - - llassert(model->mMaterialList.size() > i); - const std::string& binding = instance.mModel->mMaterialList[i]; - const LLImportMaterial& material = instance.mMaterial[binding]; - - buffer->setBuffer(type_mask & buffer->getTypeMask()); - gGL.diffuseColor4fv(material.mDiffuseColor.mV); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - // Find the tex for this material, bind it, and add it to our set - // - LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); - if (tex) - { - mTextureSet.insert(tex); - } - - buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - - if (edges) - { - 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); - glLineWidth(1.f); - } - } - } - } - } - - if (joint_positions) - { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - gDebugProgram.bind(); - } - getPreviewAvatar()->renderCollisionVolumes(); - 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(); - } - } - } - - if (use_shaders) - { - gObjectPreviewProgram.unbind(); - } - - gGL.popMatrix(); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// refresh() -//----------------------------------------------------------------------------- -void LLModelPreview::refresh() -{ - mNeedsUpdate = TRUE; -} - -//----------------------------------------------------------------------------- -// rotate() -//----------------------------------------------------------------------------- -void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) -{ - mCameraYaw = mCameraYaw + yaw_radians; - - mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); -} - -//----------------------------------------------------------------------------- -// zoom() -//----------------------------------------------------------------------------- -void LLModelPreview::zoom(F32 zoom_amt) -{ - F32 new_zoom = mCameraZoom+zoom_amt; - // 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) -{ - 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) -{ - lod = llclamp(lod, 0, (S32) LLModel::LOD_HIGH); - - if (lod != mPreviewLOD) - { - mPreviewLOD = lod; - - LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo"); - 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]); - - LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); - LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); - - for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) - { - const LLColor4& color = (i == lod) ? highlight_color : normal_color; - - mFMP->childSetColor(lod_status_name[i], color); - mFMP->childSetColor(lod_label_name[i], color); - 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(); -} - -void LLFloaterModelPreview::onBrowseLOD(S32 lod) -{ - assert_main_thread(); - - loadModel(lod); -} - -//static -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(); - - mp = fmp->mModelPreview; - mp->loadModel(filename,LLModel::LOD_HIGH,true); -} - -//static -void LLFloaterModelPreview::onUpload(void* user_data) -{ - assert_main_thread(); - - LLFloaterModelPreview* mp = (LLFloaterModelPreview*) user_data; - mp->clearLogTab(); - - mp->mUploadBtn->setEnabled(false); - - mp->mModelPreview->rebuildUploadData(); - - bool upload_skinweights = mp->childGetValue("upload_skin").asBoolean(); - bool upload_joint_positions = mp->childGetValue("upload_joints").asBoolean(); - bool lock_scale_if_joint_position = mp->childGetValue("lock_scale_if_joint_position").asBoolean(); - - if (gSavedSettings.getBOOL("MeshImportUseSLM")) - { - mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions, lock_scale_if_joint_position); - } - - gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), - upload_skinweights, upload_joint_positions, lock_scale_if_joint_position, - mp->mUploadModelUrl, - true, LLHandle<LLWholeModelFeeObserver>(), mp->getWholeModelUploadObserverHandle()); -} - - -void LLFloaterModelPreview::refresh() +void LLFloaterModelPreview::refresh() { sInstance->toggleCalculateButton(true); sInstance->mModelPreview->mDirty = true; } -//static -void LLModelPreview::textureLoadedCallback( - BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* src_aux, - S32 discard_level, - BOOL final, - void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); - - if(final && preview->mModelLoader) - { - if(preview->mModelLoader->mNumOfFetchingTextures > 0) - { - preview->mModelLoader->mNumOfFetchingTextures-- ; - } - } -} - -// static -bool LLModelPreview::lodQueryCallback() -{ - // not the best solution, but model preview belongs to floater - // so it is an easy way to check that preview still exists. - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp && fmp->mModelPreview) - { - LLModelPreview* preview = fmp->mModelPreview; - if (preview->mLodsQuery.size() > 0) - { - S32 lod = preview->mLodsQuery.back(); - preview->mLodsQuery.pop_back(); - preview->genLODs(lod); - - // return false to continue cycle - return false; - } - } - // nothing to process - return true; -} - -void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) -{ - if (!mLODFrozen) - { - genLODs(lod, 3, enforce_tri_limit); - refresh(); - } -} - LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) { mStage = stage; diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 6f78d534f3..ca52312756 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -28,37 +28,14 @@ #define LL_LLFLOATERMODELPREVIEW_H #include "llfloaternamedesc.h" - -#include "lldynamictexture.h" -#include "llquaternion.h" -#include "llmeshrepository.h" -#include "llmodel.h" -#include "llthread.h" -#include "llviewermenufile.h" #include "llfloatermodeluploadbase.h" - -#include "lldaeloader.h" +#include "llmeshrepository.h" class LLComboBox; class LLJoint; -class LLViewerJointMesh; -class LLVOAvatar; -class LLTextBox; -class LLVertexBuffer; +class LLMeshFilePicker; class LLModelPreview; -class LLFloaterModelPreview; -class DAE; -class daeElement; -class domProfile_COMMON; -class domInstance_geometry; -class domNode; -class domTranslate; -class domController; -class domSkin; -class domMesh; -class LLMenuButton; class LLTabContainer; -class LLToggleableMenu; class LLViewerTextEditor; @@ -255,209 +232,4 @@ private: joint_override_data_map_t mJointOverrides[LLModel::NUM_LODS]; }; -class LLMeshFilePicker : public LLFilePickerThread -{ -public: - LLMeshFilePicker(LLModelPreview* mp, S32 lod); - virtual void notify(const std::vector<std::string>& filenames); - -private: - LLModelPreview* mMP; - S32 mLOD; -}; - - -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; - -public: - - typedef enum - { - LOD_FROM_FILE = 0, - GENERATE, - USE_LOD_ABOVE, - } eLoDMode; - -public: - LLModelPreview(S32 width, S32 height, LLFloater* fmp); - virtual ~LLModelPreview(); - - void resetPreviewTarget(); - void setPreviewTarget(F32 distance); - void setTexture(U32 name) { mTextureName = name; } - - void setPhysicsFromLOD(S32 lod); - BOOL render(); - void update(); - void genBuffers(S32 lod, bool skinned); - void clearBuffers(); - void refresh(); - void rotate(F32 yaw_radians, F32 pitch_radians); - void zoom(F32 zoom_amt); - void pan(F32 right, F32 up); - virtual BOOL needsRender() { return mNeedsUpdate; } - void setPreviewLOD(S32 lod); - void clearModel(S32 lod); - void getJointAliases(JointMap& joint_map); - void loadModel(std::string filename, S32 lod, bool force_disable_slm = false); - void loadModelCallback(S32 lod); - bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } - void queryLODs() { mGenLOD = true; }; - void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); - void generateNormals(); - void restoreNormals(); - U32 calcResourceCost(); - void rebuildUploadData(); - void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); - void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); - void clearIncompatible(S32 lod); - void updateStatusMessages(); - void updateLodControls(S32 lod); - void clearGLODGroup(); - void onLODParamCommit(S32 lod, bool enforce_tri_limit); - void addEmptyFace( LLModel* pTarget ); - - const bool getModelPivot( void ) const { return mHasPivot; } - void setHasPivot( bool val ) { mHasPivot = val; } - void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } - - //Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions - //Accessors for joint position upload friendly rigs - const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } - void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } - - //Accessors for the legacy rigs - 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(); - - boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); } - boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){ return mModelLoadedSignal.connect(cb); } - boost::signals2::connection setModelUpdatedCallback( const model_updated_signal_t::slot_type& cb ){ return mModelUpdatedSignal.connect(cb); } - - void setLoadState( U32 state ) { mLoadState = state; } - U32 getLoadState() { return mLoadState; } - - static bool sIgnoreLoadedCallback; - std::vector<S32> mLodsQuery; - std::vector<S32> mLodsWithParsingError; - bool mHasDegenerate; - -protected: - - static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque); - static void stateChangedCallback(U32 state, void* opaque); - - static LLJoint* lookupJointByName(const std::string&, void* opaque); - static U32 loadTextures(LLImportMaterial& material, void* opaque); - -private: - //Utility function for controller vertex compare - bool verifyCount( int expected, int result ); - //Creates the dummy avatar for the preview window - void createPreviewAvatar( void ); - //Accessor for the dummy avatar - LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } - // Count amount of original models, excluding sub-models - static U32 countRootModels(LLModelLoader::model_list models); - - protected: - friend class LLModelLoader; - friend class LLFloaterModelPreview; - friend class LLFloaterModelPreview::DecompRequest; - friend class LLPhysicsDecomp; - - LLFloater* mFMP; - - BOOL mNeedsUpdate; - bool mDirty; - bool mGenLOD; - U32 mTextureName; - F32 mCameraDistance; - F32 mCameraYaw; - F32 mCameraPitch; - F32 mCameraZoom; - LLVector3 mCameraOffset; - LLVector3 mPreviewTarget; - LLVector3 mPreviewScale; - S32 mPreviewLOD; - S32 mPhysicsSearchLOD; - U32 mResourceCost; - std::string mLODFile[LLModel::NUM_LODS]; - bool mLoading; - U32 mLoadState; - bool mResetJoints; - bool mModelNoErrors; - - std::map<std::string, bool> mViewOption; - - //GLOD object parameters (must rebuild object if these change) - bool mLODFrozen; - F32 mBuildShareTolerance; - U32 mBuildQueueMode; - U32 mBuildOperator; - U32 mBuildBorderMode; - U32 mRequestedLoDMode[LLModel::NUM_LODS]; - S32 mRequestedTriangleCount[LLModel::NUM_LODS]; - F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; - U32 mRequestedBuildOperator[LLModel::NUM_LODS]; - U32 mRequestedQueueMode[LLModel::NUM_LODS]; - U32 mRequestedBorderMode[LLModel::NUM_LODS]; - F32 mRequestedShareTolerance[LLModel::NUM_LODS]; - F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; - - LLModelLoader* mModelLoader; - - LLModelLoader::scene mScene[LLModel::NUM_LODS]; - LLModelLoader::scene mBaseScene; - - LLModelLoader::model_list mModel[LLModel::NUM_LODS]; - LLModelLoader::model_list mBaseModel; - - typedef std::vector<LLVolumeFace> v_LLVolumeFace_t; - typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t; - - vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS]; - vv_LLVolumeFace_t mBaseModelFacesCopy; - - U32 mGroup; - std::map<LLPointer<LLModel>, U32> mObject; - U32 mMaxTriangleLimit; - - LLMeshUploadThread::instance_list mUploadData; - std::set<LLViewerFetchedTexture * > mTextureSet; - - //map of vertex buffers to models (one vertex buffer in vector per face in model - std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; - - details_signal_t mDetailsSignal; - model_loaded_signal_t mModelLoadedSignal; - model_updated_signal_t mModelUpdatedSignal; - - LLVector3 mModelPivot; - bool mHasPivot; - - float mPelvisZOffset; - - bool mRigValidJointUpload; - U32 mLegacyRigFlags; - - bool mLastJointUpdate; - - JointNameSet mJointsFromNode; - JointTransformMap mJointTransformMap; - - LLPointer<LLVOAvatar> mPreviewAvatar; - LLCachedControl<bool> mImporterDebug; -}; - #endif // LL_LLFLOATERMODELPREVIEW_H diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp new file mode 100644 index 0000000000..96af3b37d9 --- /dev/null +++ b/indra/newview/llmodelpreview.cpp @@ -0,0 +1,3507 @@ +/** + * @file llmodelpreview.cpp + * @brief LLModelPreview class implementation + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llmodelloader.h" +#include "lldaeloader.h" +#include "llfloatermodelpreview.h" + +#include "llmodelpreview.h" + +#include "llimagebmp.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llagent.h" +#include "llanimationstates.h" +#include "llcallbacklist.h" +#include "lldatapacker.h" +#include "lldrawable.h" +#include "llface.h" +#include "lliconctrl.h" +#include "llmatrix4a.h" +#include "llmeshrepository.h" +#include "llrender.h" +#include "llsdutil_math.h" +#include "llskinningutil.h" +#include "llstring.h" +#include "llsdserialize.h" +#include "lltoolmgr.h" +#include "llui.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewerobjectlist.h" +#include "llviewernetwork.h" +#include "llviewershadermgr.h" +#include "llviewertexteditor.h" +#include "llviewertexturelist.h" +#include "llvoavatar.h" +#include "pipeline.h" + +// ui controls (from floater) +#include "llbutton.h" +#include "llcombobox.h" +#include "llspinctrl.h" +#include "lltabcontainer.h" +#include "lltextbox.h" + +#include "glod/glod.h" +#include <boost/algorithm/string.hpp> + +bool LLModelPreview::sIgnoreLoadedCallback = false; + +const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; + +BOOL stop_gloderror() +{ + GLuint error = glodGetError(); + + if (error != GLOD_NO_ERROR) + { + LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; + return TRUE; + } + + return FALSE; +} + +LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) +{ + LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); + + if (texture) + { + if (texture->getDiscardLevel() > -1) + { + gGL.getTexUnit(0)->bind(texture, true); + return texture; + } + } + + return NULL; +} + +std::string stripSuffix(std::string name) +{ + if ((name.find("_LOD") != -1) || (name.find("_PHYS") != -1)) + { + return name.substr(0, name.rfind('_')); + } + return name; +} + +void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +{ + LLModelLoader::scene::iterator base_iter = scene.begin(); + bool found = false; + while (!found && (base_iter != scene.end())) + { + matOut = base_iter->first; + + LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); + while (!found && (base_instance_iter != base_iter->second.end())) + { + LLModelInstance& base_instance = *base_instance_iter++; + LLModel* base_model = base_instance.mModel; + + if (base_model && (base_model->mLabel == name_to_match)) + { + baseModelOut = base_model; + return; + } + } + base_iter++; + } +} + +//----------------------------------------------------------------------------- +// LLModelPreview +//----------------------------------------------------------------------------- + +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) + : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() + , mLodsQuery() + , mLodsWithParsingError() + , mPelvisZOffset(0.0f) + , 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; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 0; + mModelLoader = NULL; + mMaxTriangleLimit = 0; + mDirty = false; + mGenLOD = false; + mLoading = false; + mLoadState = LLModelLoader::STARTING; + mGroup = 0; + mLODFrozen = false; + mBuildShareTolerance = 0.f; + mBuildQueueMode = GLOD_QUEUE_GREEDY; + mBuildBorderMode = GLOD_BORDER_UNLOCK; + mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; + + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) + { + mRequestedTriangleCount[i] = 0; + mRequestedCreaseAngle[i] = -1.f; + mRequestedLoDMode[i] = 0; + mRequestedErrorThreshold[i] = 0.f; + mRequestedBuildOperator[i] = 0; + mRequestedQueueMode[i] = 0; + mRequestedBorderMode[i] = 0; + mRequestedShareTolerance[i] = 0.f; + } + + mViewOption["show_textures"] = false; + + mFMP = fmp; + + mHasPivot = false; + mModelPivot = LLVector3(0.0f, 0.0f, 0.0f); + + glodInit(); + + createPreviewAvatar(); +} + +LLModelPreview::~LLModelPreview() +{ + // glod apparently has internal mem alignment issues that are angering + // the heap-check code in windows, these should be hunted down in that + // TP code, if possible + // + // kernel32.dll!HeapFree() + 0x14 bytes + // msvcr100.dll!free(void * pBlock) Line 51 C + // glod.dll!glodGetGroupParameteriv() + 0x119 bytes + // glod.dll!glodShutdown() + 0x77 bytes + // + //glodShutdown(); + if (mModelLoader) + { + mModelLoader->shutdown(); + } +} + +U32 LLModelPreview::calcResourceCost() +{ + assert_main_thread(); + + rebuildUploadData(); + + //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed. + if (mFMP && mFMP->childGetValue("upload_skin").asBoolean()) + { + bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); + if (uploadingJointPositions && !isRigValidForJointPositionUpload()) + { + mFMP->childDisable("ok_btn"); + } + } + + std::set<LLModel*> accounted; + U32 num_points = 0; + U32 num_hulls = 0; + + F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f; + + if (mFMP && mFMP->childGetValue("upload_joints").asBoolean()) + { + // FIXME if preview avatar ever gets reused, this fake mesh ID stuff will fail. + // see also call to addAttachmentPosOverride. + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + getPreviewAvatar()->addPelvisFixup(mPelvisZOffset, fake_mesh_id); + } + + F32 streaming_cost = 0.f; + F32 physics_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (accounted.find(instance.mModel) == accounted.end()) + { + accounted.insert(instance.mModel); + + LLModel::Decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : + instance.mModel->mPhysics; + + //update instance skin info for each lods pelvisZoffset + for (int j = 0; j<LLModel::NUM_LODS; ++j) + { + if (instance.mLOD[j]) + { + instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset; + } + } + + std::stringstream ostr; + LLSD ret = LLModel::writeModel(ostr, + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + mFMP->childGetValue("lock_scale_if_joint_position").asBoolean(), + TRUE, + FALSE, + instance.mModel->mSubmodelID); + + num_hulls += decomp.mHull.size(); + for (U32 i = 0; i < decomp.mHull.size(); ++i) + { + num_points += decomp.mHull[i].size(); + } + + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; + + LLVector3 position = LLVector3(0, 0, 0) * transformation; + + LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + LLVector3 scale = LLVector3(x_length, y_length, z_length); + + F32 radius = scale.length()*0.5f*debug_scale; + + LLMeshCostData costs; + if (gMeshRepo.getCostData(ret, costs)) + { + streaming_cost += costs.getRadiusBasedStreamingCost(radius); + } + } + } + + F32 scale = mFMP ? mFMP->childGetValue("import_scale").asReal()*2.f : 2.f; + + mDetailsSignal(mPreviewScale[0] * scale, mPreviewScale[1] * scale, mPreviewScale[2] * scale, streaming_cost, physics_cost); + + updateStatusMessages(); + + return (U32)streaming_cost; +} + +void LLModelPreview::rebuildUploadData() +{ + assert_main_thread(); + + mUploadData.clear(); + mTextureSet.clear(); + + //fill uploaddata instance vectors from scene data + + std::string requested_name = mFMP->getChild<LLUICtrl>("description_form")->getValue().asString(); + + LLSpinCtrl* scale_spinner = mFMP->getChild<LLSpinCtrl>("import_scale"); + + F32 scale = scale_spinner->getValue().asReal(); + + LLMatrix4 scale_mat; + scale_mat.initScale(LLVector3(scale, scale, scale)); + + F32 max_scale = 0.f; + + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); + + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) + { //for each transform in scene + LLMatrix4 mat = iter->first; + + // compute position + LLVector3 position = LLVector3(0, 0, 0) * mat; + + // compute scale + LLVector3 x_transformed = LLVector3(1, 0, 0) * mat - position; + LLVector3 y_transformed = LLVector3(0, 1, 0) * mat - position; + LLVector3 z_transformed = LLVector3(0, 0, 1) * mat - position; + F32 x_length = x_transformed.normalize(); + F32 y_length = y_transformed.normalize(); + F32 z_length = z_transformed.normalize(); + + max_scale = llmax(llmax(llmax(max_scale, x_length), y_length), z_length); + + mat *= scale_mat; + + for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) + { //for each instance with said transform applied + LLModelInstance instance = *model_iter++; + + LLModel* base_model = instance.mModel; + + if (base_model && !requested_name.empty()) + { + base_model->mRequestedLabel = requested_name; + } + + for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) + { + LLModel* lod_model = NULL; + if (!legacyMatching) + { + // Fill LOD slots by finding matching meshes by label with name extensions + // in the appropriate scene for each LOD. This fixes all kinds of issues + // where the indexed method below fails in spectacular fashion. + // If you don't take the time to name your LOD and PHYS meshes + // with the name of their corresponding mesh in the HIGH LOD, + // then the indexed method will be attempted below. + + LLMatrix4 transform; + + std::string name_to_match = instance.mLabel; + llassert(!name_to_match.empty()); + + int extensionLOD; + if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty()) + { + extensionLOD = i; + } + else + { + //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for + extensionLOD = mPhysicsSearchLOD; + } + + std::string toAdd; + switch (extensionLOD) + { + case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; + case LLModel::LOD_LOW: toAdd = "_LOD1"; break; + case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; + case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (name_to_match.find(toAdd) == -1) + { + name_to_match += toAdd; + } + + FindModel(mScene[i], name_to_match, lod_model, transform); + + if (!lod_model && i != LLModel::LOD_PHYSICS) + { + 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; + while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) + { + std::string name_to_match = instance.mLabel; + llassert(!name_to_match.empty()); + + std::string toAdd; + switch (searchLOD) + { + case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; + case LLModel::LOD_LOW: toAdd = "_LOD1"; break; + case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; + case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (name_to_match.find(toAdd) == -1) + { + name_to_match += toAdd; + } + + // See if we can find an appropriately named model in LOD 'searchLOD' + // + FindModel(mScene[searchLOD], name_to_match, lod_model, transform); + searchLOD++; + } + } + } + else + { + // Use old method of index-based association + U32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { + // find reference instance for this model + if (mBaseModel[idx] == base_model) + { + if (mImporterDebug) + { + 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; + } + } + + // If the model list for the current LOD includes that index... + // + if (mModel[i].size() > idx) + { + // Assign that index from the model list for our LOD as the LOD model for this instance + // + lod_model = mModel[i][idx]; + 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 (mImporterDebug) + { + 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 (mImporterDebug) + { + std::ostringstream out; + if (i == LLModel::LOD_PHYSICS) + { + out << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel; + } + else + { + 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; + } + else + { + if (i < LLModel::LOD_HIGH && !lodsReady()) + { + // assign a placeholder from previous LOD until lod generation is complete. + // 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 (mImporterDebug) + { + std::ostringstream out; + out << "List of models does not include " << instance.mLabel; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + } + } + + LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; + if (!high_lod_model) + { + setLoadState(LLModelLoader::ERROR_MATERIALS); + mFMP->childDisable("calculate_btn"); + } + else + { + for (U32 i = 0; i < LLModel::NUM_LODS - 1; i++) + { + int refFaceCnt = 0; + int modelFaceCnt = 0; + llassert(instance.mLOD[i]); + if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt)) + { + setLoadState(LLModelLoader::ERROR_MATERIALS); + mFMP->childDisable("calculate_btn"); + } + } + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)mFMP; + bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean(); + if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0) + { + LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix); + LLQuaternion identity; + if (!bind_rot.isEqualEps(identity, 0.01)) + { + 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); + } + } + } + instance.mTransform = mat; + mUploadData.push_back(instance); + } + } + + for (U32 lod = 0; lod < LLModel::NUM_LODS - 1; lod++) + { + // Search for models that are not included into upload data + // If we found any, that means something we loaded is not a sub-model. + for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind) + { + bool found_model = false; + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + if (instance.mLOD[lod] == mModel[lod][model_ind]) + { + found_model = true; + break; + } + } + if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) + { + 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"); + } + } + } + + F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE - 0.1f) / max_scale; + + F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); + max_axis = llmax(max_axis, mPreviewScale.mV[2]); + max_axis *= 2.f; + + //clamp scale so that total imported model bounding box is smaller than 240m on a side + max_import_scale = llmin(max_import_scale, 240.f / max_axis); + + scale_spinner->setMaxValue(max_import_scale); + + if (max_import_scale < scale) + { + scale_spinner->setValue(max_import_scale); + } + +} + +void LLModelPreview::saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) +{ + if (!mLODFile[LLModel::LOD_HIGH].empty()) + { + std::string filename = mLODFile[LLModel::LOD_HIGH]; + std::string slm_filename; + + if (LLModelLoader::getSLMFilename(filename, slm_filename)) + { + saveUploadData(slm_filename, save_skinweights, save_joint_positions, lock_scale_if_joint_position); + } + } +} + +void LLModelPreview::saveUploadData(const std::string& filename, + bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position) +{ + + std::set<LLPointer<LLModel> > meshes; + std::map<LLModel*, std::string> mesh_binary; + + LLModel::hull empty_hull; + + LLSD data; + + data["version"] = SLM_SUPPORTED_VERSION; + if (!mBaseModel.empty()) + { + data["name"] = mBaseModel[0]->getName(); + } + + S32 mesh_id = 0; + + //build list of unique models and initialize local id + for (U32 i = 0; i < mUploadData.size(); ++i) + { + LLModelInstance& instance = mUploadData[i]; + + if (meshes.find(instance.mModel) == meshes.end()) + { + instance.mModel->mLocalID = mesh_id++; + meshes.insert(instance.mModel); + + std::stringstream str; + LLModel::Decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : + instance.mModel->mPhysics; + + LLModel::writeModel(str, + instance.mLOD[LLModel::LOD_PHYSICS], + instance.mLOD[LLModel::LOD_HIGH], + instance.mLOD[LLModel::LOD_MEDIUM], + instance.mLOD[LLModel::LOD_LOW], + instance.mLOD[LLModel::LOD_IMPOSTOR], + decomp, + save_skinweights, + save_joint_positions, + lock_scale_if_joint_position, + FALSE, TRUE, instance.mModel->mSubmodelID); + + data["mesh"][instance.mModel->mLocalID] = str.str(); + } + + data["instance"][i] = instance.asLLSD(); + } + + llofstream out(filename.c_str(), std::ios_base::out | std::ios_base::binary); + LLSDSerialize::toBinary(data, out); + out.flush(); + out.close(); +} + +void LLModelPreview::clearModel(S32 lod) +{ + if (lod < 0 || lod > LLModel::LOD_PHYSICS) + { + return; + } + + mVertexBuffer[lod].clear(); + mModel[lod].clear(); + mScene[lod].clear(); +} + +void LLModelPreview::getJointAliases(JointMap& joint_map) +{ + // Get all standard skeleton joints from the preview avatar. + LLVOAvatar *av = getPreviewAvatar(); + + //Joint names and aliases come from avatar_skeleton.xml + + joint_map = av->getJointAliases(); + + std::vector<std::string> cv_names, attach_names; + av->getSortedJointNames(1, cv_names); + av->getSortedJointNames(2, attach_names); + for (std::vector<std::string>::iterator it = cv_names.begin(); it != cv_names.end(); ++it) + { + joint_map[*it] = *it; + } + for (std::vector<std::string>::iterator it = attach_names.begin(); it != attach_names.end(); ++it) + { + joint_map[*it] = *it; + } +} + +void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm) +{ + assert_main_thread(); + + LLMutexLock lock(this); + + if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::NUM_LODS - 1) + { + 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; + } + + // This triggers if you bring up the file picker and then hit CANCEL. + // Just use the previous model (if any) and ignore that you brought up + // the file picker. + + if (filename.empty()) + { + if (mBaseModel.empty()) + { + // this is the initial file picking. Close the whole floater + // if we don't have a base model to show for high LOD. + mFMP->closeFloater(false); + } + mLoading = false; + return; + } + + if (mModelLoader) + { + LL_WARNS() << "Incompleted model load operation pending." << LL_ENDL; + return; + } + + mLODFile[lod] = filename; + + if (lod == LLModel::LOD_HIGH) + { + clearGLODGroup(); + } + + std::map<std::string, std::string> joint_alias_map; + getJointAliases(joint_alias_map); + + mModelLoader = new LLDAELoader( + filename, + lod, + &LLModelPreview::loadedCallback, + &LLModelPreview::lookupJointByName, + &LLModelPreview::loadTextures, + &LLModelPreview::stateChangedCallback, + this, + mJointTransformMap, + mJointsFromNode, + joint_alias_map, + LLSkinningUtil::getMaxJointCount(), + gSavedSettings.getU32("ImporterModelLimit"), + gSavedSettings.getBOOL("ImporterPreprocessDAE")); + + if (force_disable_slm) + { + mModelLoader->mTrySLM = false; + } + else + { + // For MAINT-6647, we have set force_disable_slm to true, + // which means this code path will never be taken. Trying to + // re-use SLM files has never worked properly; in particular, + // it tends to force the UI into strange checkbox options + // which cannot be altered. + + //only try to load from slm if viewer is configured to do so and this is the + //initial model load (not an LoD or physics shape) + mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); + } + mModelLoader->start(); + + mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); + + setPreviewLOD(lod); + + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mFMP->childDisable("ok_btn"); + mFMP->childDisable("calculate_btn"); + } + + if (lod == mPreviewLOD) + { + mFMP->childSetValue("lod_file_" + lod_name[lod], mLODFile[lod]); + } + else if (lod == LLModel::LOD_PHYSICS) + { + mFMP->childSetValue("physics_file", mLODFile[lod]); + } + + mFMP->openFloater(); +} + +void LLModelPreview::setPhysicsFromLOD(S32 lod) +{ + assert_main_thread(); + + if (lod >= 0 && lod <= 3) + { + mPhysicsSearchLOD = lod; + mModel[LLModel::LOD_PHYSICS] = mModel[lod]; + mScene[LLModel::LOD_PHYSICS] = mScene[lod]; + mLODFile[LLModel::LOD_PHYSICS].clear(); + mFMP->childSetValue("physics_file", mLODFile[LLModel::LOD_PHYSICS]); + mVertexBuffer[LLModel::LOD_PHYSICS].clear(); + rebuildUploadData(); + refresh(); + updateStatusMessages(); + } +} + +void LLModelPreview::clearIncompatible(S32 lod) +{ + //Don't discard models if specified model is the physic rep + if (lod == LLModel::LOD_PHYSICS) + { + return; + } + + // at this point we don't care about sub-models, + // different amount of sub-models means face count mismatch, not incompatibility + U32 lod_size = countRootModels(mModel[lod]); + for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) + { //clear out any entries that aren't compatible with this model + if (i != lod) + { + if (countRootModels(mModel[i]) != lod_size) + { + mModel[i].clear(); + mScene[i].clear(); + mVertexBuffer[i].clear(); + + if (i == LLModel::LOD_HIGH) + { + mBaseModel = mModel[lod]; + clearGLODGroup(); + mBaseScene = mScene[lod]; + mVertexBuffer[5].clear(); + } + } + } + } +} + +void LLModelPreview::clearGLODGroup() +{ + if (mGroup) + { + for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) + { + glodDeleteObject(iter->second); + stop_gloderror(); + } + mObject.clear(); + + glodDeleteGroup(mGroup); + stop_gloderror(); + mGroup = 0; + } +} + +void LLModelPreview::loadModelCallback(S32 loaded_lod) +{ + assert_main_thread(); + + LLMutexLock lock(this); + if (!mModelLoader) + { + mLoading = false; + return; + } + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mLoading = false; + mModelLoader = NULL; + mLodsWithParsingError.push_back(loaded_lod); + return; + } + + mLodsWithParsingError.erase(std::remove(mLodsWithParsingError.begin(), mLodsWithParsingError.end(), loaded_lod), mLodsWithParsingError.end()); + if (mLodsWithParsingError.empty()) + { + mFMP->childEnable("calculate_btn"); + } + + // Copy determinations about rig so UI will reflect them + // + setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); + setLegacyRigFlags(mModelLoader->getLegacyRigFlags()); + + mModelLoader->loadTextures(); + + if (loaded_lod == -1) + { //populate all LoDs from model loader scene + mBaseModel.clear(); + mBaseScene.clear(); + + bool skin_weights = false; + bool joint_overrides = false; + bool lock_scale_if_joint_position = false; + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { //for each LoD + + //clear scene and model info + mScene[lod].clear(); + mModel[lod].clear(); + mVertexBuffer[lod].clear(); + + if (mModelLoader->mScene.begin()->second[0].mLOD[lod].notNull()) + { //if this LoD exists in the loaded scene + + //copy scene to current LoD + mScene[lod] = mModelLoader->mScene; + + //touch up copied scene to look like current LoD + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + LLModelLoader::model_instance_list& list = iter->second; + + for (LLModelLoader::model_instance_list::iterator list_iter = list.begin(); list_iter != list.end(); ++list_iter) + { + //override displayed model with current LoD + list_iter->mModel = list_iter->mLOD[lod]; + + if (!list_iter->mModel) + { + continue; + } + + //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) + S32 idx = list_iter->mModel->mLocalID; + + if (mModel[lod].size() <= idx) + { //stretch model list to fit model at given index + mModel[lod].resize(idx + 1); + } + + mModel[lod][idx] = list_iter->mModel; + if (!list_iter->mModel->mSkinWeights.empty()) + { + skin_weights = true; + + if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty()) + { + joint_overrides = true; + } + if (list_iter->mModel->mSkinInfo.mLockScaleIfJointPosition) + { + lock_scale_if_joint_position = true; + } + } + } + } + } + } + + if (mFMP) + { + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)mFMP; + + if (skin_weights) + { //enable uploading/previewing of skin weights if present in .slm file + fmp->enableViewOption("show_skin_weight"); + mViewOption["show_skin_weight"] = true; + fmp->childSetValue("upload_skin", true); + } + + 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) + { + fmp->enableViewOption("lock_scale_if_joint_position"); + mViewOption["lock_scale_if_joint_position"] = true; + fmp->childSetValue("lock_scale_if_joint_position", true); + } + } + + //copy high lod to base scene for LoD generation + mBaseScene = mScene[LLModel::LOD_HIGH]; + mBaseModel = mModel[LLModel::LOD_HIGH]; + + mDirty = true; + resetPreviewTarget(); + } + else + { //only replace given LoD + mModel[loaded_lod] = mModelLoader->mModelList; + mScene[loaded_lod] = mModelLoader->mScene; + mVertexBuffer[loaded_lod].clear(); + + setPreviewLOD(loaded_lod); + + if (loaded_lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation + if (mBaseModel.empty()) + { //first time we've loaded a model, auto-gen LoD + mGenLOD = true; + } + + mBaseModel = mModel[loaded_lod]; + clearGLODGroup(); + + mBaseScene = mScene[loaded_lod]; + mVertexBuffer[5].clear(); + } + else + { + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); + if (!legacyMatching) + { + if (!mBaseModel.empty()) + { + BOOL name_based = FALSE; + BOOL has_submodels = FALSE; + for (U32 idx = 0; idx < mBaseModel.size(); ++idx) + { + if (mBaseModel[idx]->mSubmodelID) + { // don't do index-based renaming when the base model has submodels + has_submodels = TRUE; + if (mImporterDebug) + { + std::ostringstream out; + out << "High LOD has submodels"; + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + } + break; + } + } + + for (U32 idx = 0; idx < mModel[loaded_lod].size(); ++idx) + { + std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); + + LLModel* found_model = NULL; + LLMatrix4 transform; + FindModel(mBaseScene, loaded_name, found_model, transform); + if (found_model) + { // don't rename correctly named models (even if they are placed in a wrong order) + name_based = TRUE; + } + + if (mModel[loaded_lod][idx]->mSubmodelID) + { // don't rename the models when loaded LOD model has submodels + has_submodels = TRUE; + } + } + + if (mImporterDebug) + { + 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) + { // replace the name of the model loaded for any non-HIGH LOD to match the others (MAINT-5601) + // this actually works like "ImporterLegacyMatching" for this particular LOD + for (U32 idx = 0; idx < mModel[loaded_lod].size() && idx < mBaseModel.size(); ++idx) + { + std::string name = mBaseModel[idx]->mLabel; + std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); + + if (loaded_name != name) + { + switch (loaded_lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (mImporterDebug) + { + 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; + } + } + } + } + } + } + + clearIncompatible(loaded_lod); + + mDirty = true; + + if (loaded_lod == LLModel::LOD_HIGH) + { + resetPreviewTarget(); + } + } + + mLoading = false; + if (mFMP) + { + if (!mBaseModel.empty()) + { + const std::string& model_name = mBaseModel[0]->getName(); + LLLineEditor* description_form = mFMP->getChild<LLLineEditor>("description_form"); + if (description_form->getText().empty()) + { + 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(); + + mModelLoadedSignal(); + + mModelLoader = NULL; +} + +void LLModelPreview::resetPreviewTarget() +{ + if (mModelLoader) + { + mPreviewTarget = (mModelLoader->mExtents[0] + mModelLoader->mExtents[1]) * 0.5f; + mPreviewScale = (mModelLoader->mExtents[1] - mModelLoader->mExtents[0]) * 0.5f; + } + + setPreviewTarget(mPreviewScale.magVec()*10.f); +} + +void LLModelPreview::generateNormals() +{ + assert_main_thread(); + + S32 which_lod = mPreviewLOD; + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + F32 angle_cutoff = mFMP->childGetValue("crease_angle").asReal(); + + mRequestedCreaseAngle[which_lod] = angle_cutoff; + + angle_cutoff *= DEG_TO_RAD; + + if (which_lod == 3 && !mBaseModel.empty()) + { + if (mBaseModelFacesCopy.empty()) + { + mBaseModelFacesCopy.reserve(mBaseModel.size()); + for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) + { + v_LLVolumeFace_t faces; + (*it)->copyFacesTo(faces); + mBaseModelFacesCopy.push_back(faces); + } + } + + for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) + { + (*it)->generateNormals(angle_cutoff); + } + + mVertexBuffer[5].clear(); + } + + bool perform_copy = mModelFacesCopy[which_lod].empty(); + if (perform_copy) { + mModelFacesCopy[which_lod].reserve(mModel[which_lod].size()); + } + + for (LLModelLoader::model_list::iterator it = mModel[which_lod].begin(), itE = mModel[which_lod].end(); it != itE; ++it) + { + if (perform_copy) + { + v_LLVolumeFace_t faces; + (*it)->copyFacesTo(faces); + mModelFacesCopy[which_lod].push_back(faces); + } + + (*it)->generateNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + updateStatusMessages(); +} + +void LLModelPreview::restoreNormals() +{ + S32 which_lod = mPreviewLOD; + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + if (!mBaseModelFacesCopy.empty()) + { + llassert(mBaseModelFacesCopy.size() == mBaseModel.size()); + + vv_LLVolumeFace_t::const_iterator itF = mBaseModelFacesCopy.begin(); + for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it, ++itF) + { + (*it)->copyFacesFrom((*itF)); + } + + mBaseModelFacesCopy.clear(); + } + + if (!mModelFacesCopy[which_lod].empty()) + { + vv_LLVolumeFace_t::const_iterator itF = mModelFacesCopy[which_lod].begin(); + for (LLModelLoader::model_list::iterator it = mModel[which_lod].begin(), itE = mModel[which_lod].end(); it != itE; ++it, ++itF) + { + (*it)->copyFacesFrom((*itF)); + } + + mModelFacesCopy[which_lod].clear(); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + updateStatusMessages(); +} + +void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +{ + // Allow LoD from -1 to LLModel::LOD_PHYSICS + if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) + { + 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; + } + + if (mBaseModel.empty()) + { + return; + } + + LLVertexBuffer::unbind(); + + bool no_ff = LLGLSLShader::sNoFixedFunction; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + LLGLSLShader::sNoFixedFunction = false; + + if (shader) + { + shader->unbind(); + } + + stop_gloderror(); + static U32 cur_name = 1; + + S32 limit = -1; + + U32 triangle_count = 0; + + U32 instanced_triangle_count = 0; + + //get the triangle count for the whole scene + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) + { + for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) + { + LLModel* mdl = instance->mModel; + if (mdl) + { + instanced_triangle_count += mdl->getNumTriangles(); + } + } + } + + //get the triangle count for the non-instanced set of models + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + triangle_count += mBaseModel[i]->getNumTriangles(); + } + + //get ratio of uninstanced triangles to instanced triangles + F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count; + + U32 base_triangle_count = triangle_count; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + U32 lod_mode = 0; + + F32 lod_error_threshold = 0; + + // The LoD should be in range from Lowest to High + if (which_lod > -1 && which_lod < NUM_LOD) + { + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } + + lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); + } + + if (which_lod != -1) + { + mRequestedLoDMode[which_lod] = lod_mode; + } + + if (lod_mode == 0) + { + lod_mode = GLOD_TRIANGLE_BUDGET; + + // The LoD should be in range from Lowest to High + if (which_lod > -1 && which_lod < NUM_LOD) + { + limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); + //convert from "scene wide" to "non-instanced" triangle limit + limit = (S32)((F32)limit*triangle_ratio); + } + } + else + { + lod_mode = GLOD_ERROR_THRESHOLD; + } + + bool object_dirty = false; + + if (mGroup == 0) + { + object_dirty = true; + mGroup = cur_name++; + glodNewGroup(mGroup); + } + + if (object_dirty) + { + for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + { //build GLOD objects for each model in base model list + LLModel* mdl = *iter; + + if (mObject[mdl] != 0) + { + glodDeleteObject(mObject[mdl]); + } + + mObject[mdl] = cur_name++; + + glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); + stop_gloderror(); + + if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) + { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation + mVertexBuffer[5].clear(); + } + + if (mVertexBuffer[5].empty()) + { + genBuffers(5, false); + } + + U32 tri_count = 0; + for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + { + LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; + buff->setBuffer(type_mask & buff->getTypeMask()); + + U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); + if (num_indices > 2) + { + glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); + } + tri_count += num_indices / 3; + stop_gloderror(); + } + + glodBuildObject(mObject[mdl]); + stop_gloderror(); + } + } + + + S32 start = LLModel::LOD_HIGH; + S32 end = 0; + + if (which_lod != -1) + { + start = end = which_lod; + } + + mMaxTriangleLimit = base_triangle_count; + + for (S32 lod = start; lod >= end; --lod) + { + if (which_lod == -1) + { + if (lod < start) + { + triangle_count /= decimation; + } + } + else + { + if (enforce_tri_limit) + { + triangle_count = limit; + } + else + { + for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j) + { + triangle_count /= decimation; + } + } + } + + mModel[lod].clear(); + mModel[lod].resize(mBaseModel.size()); + mVertexBuffer[lod].clear(); + + U32 actual_tris = 0; + U32 actual_verts = 0; + U32 submeshes = 0; + + mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio); + mRequestedErrorThreshold[lod] = lod_error_threshold; + + glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); + stop_gloderror(); + + glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); + stop_gloderror(); + + glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); + stop_gloderror(); + + if (lod_mode != GLOD_TRIANGLE_BUDGET) + { + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); + } + else + { + //SH-632: always add 1 to desired amount to avoid decimating below desired amount + glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1); + } + + stop_gloderror(); + glodAdaptGroup(mGroup); + stop_gloderror(); + + for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) + { + LLModel* base = mBaseModel[mdl_idx]; + + GLint patch_count = 0; + glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); + stop_gloderror(); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + + std::string name = base->mLabel; + + switch (lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + mModel[lod][mdl_idx]->mLabel = name; + mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; + + GLint* sizes = new GLint[patch_count * 2]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); + stop_gloderror(); + + GLint* names = new GLint[patch_count]; + glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); + stop_gloderror(); + + mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + + LLModel* target_model = mModel[lod][mdl_idx]; + + for (GLint i = 0; i < patch_count; ++i) + { + type_mask = mVertexBuffer[5][base][i]->getTypeMask(); + + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); + + if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0) + { + if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true)) + { + // Todo: find a way to stop preview in this case instead of crashing + LL_ERRS() << "Failed buffer allocation during preview LOD generation." + << " Vertices: " << sizes[i * 2 + 1] + << " Indices: " << sizes[i * 2] << LL_ENDL; + } + buff->setBuffer(type_mask); + glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer()); + stop_gloderror(); + } + else + { + // This face was eliminated or we failed to allocate buffer, + // attempt to create a dummy triangle (one vertex, 3 indices, all 0) + buff->allocateBuffer(1, 3, true); + memset((U8*)buff->getMappedData(), 0, buff->getSize()); + memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize()); + } + + buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0); + + LLStrider<LLVector3> pos; + LLStrider<LLVector3> norm; + LLStrider<LLVector2> tc; + LLStrider<U16> index; + + buff->getVertexStrider(pos); + if (type_mask & LLVertexBuffer::MAP_NORMAL) + { + buff->getNormalStrider(norm); + } + if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + buff->getTexCoord0Strider(tc); + } + + buff->getIndexStrider(index); + + target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); + actual_tris += buff->getNumIndices() / 3; + actual_verts += buff->getNumVerts(); + ++submeshes; + + if (!validate_face(target_model->getVolumeFace(names[i]))) + { + LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; + } + } + + //blind copy skin weights and just take closest skin weight to point on + //decimated mesh for now (auto-generating LODs with skin weights is still a bit + //of an open problem). + target_model->mPosition = base->mPosition; + target_model->mSkinWeights = base->mSkinWeights; + target_model->mSkinInfo = base->mSkinInfo; + //copy material list + target_model->mMaterialList = base->mMaterialList; + + if (!validate_model(target_model)) + { + LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; + } + + delete[] sizes; + delete[] names; + } + + //rebuild scene based on mBaseScene + mScene[lod].clear(); + mScene[lod] = mBaseScene; + + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + LLModel* mdl = mBaseModel[i]; + LLModel* target = mModel[lod][i]; + if (target) + { + for (LLModelLoader::scene::iterator iter = mScene[lod].begin(); iter != mScene[lod].end(); ++iter) + { + for (U32 j = 0; j < iter->second.size(); ++j) + { + if (iter->second[j].mModel == mdl) + { + iter->second[j].mModel = target; + } + } + } + } + } + } + + mResourceCost = calcResourceCost(); + + LLVertexBuffer::unbind(); + LLGLSLShader::sNoFixedFunction = no_ff; + if (shader) + { + shader->bind(); + } +} + +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]; + std::vector<S32> submeshes[LLModel::NUM_LODS]; + + //total triangle/vertex/submesh count for each lod + S32 total_tris[LLModel::NUM_LODS]; + S32 total_verts[LLModel::NUM_LODS]; + S32 total_submeshes[LLModel::NUM_LODS]; + + for (U32 i = 0; i < LLModel::NUM_LODS - 1; i++) + { + total_tris[i] = 0; + total_verts[i] = 0; + total_submeshes[i] = 0; + } + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH]; + if (!model_high_lod) + { + setLoadState(LLModelLoader::ERROR_MATERIALS); + mFMP->childDisable("calculate_btn"); + continue; + } + + for (U32 i = 0; i < LLModel::NUM_LODS - 1; i++) + { + LLModel* lod_model = instance.mLOD[i]; + if (!lod_model) + { + setLoadState(LLModelLoader::ERROR_MATERIALS); + mFMP->childDisable("calculate_btn"); + } + else + { + //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = lod_model->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = lod_model->getVolumeFace(j); + cur_tris += face.mNumIndices / 3; + cur_verts += face.mNumVertices; + } + + std::string instance_name = instance.mLabel; + + 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. + // + 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()) + { + out << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter); + LL_INFOS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + out.str(""); + mat_iter++; + } + } + + //add this model to the lod total + total_tris[i] += cur_tris; + total_verts[i] += cur_verts; + total_submeshes[i] += cur_submeshes; + + //store this model's counts to asset data + tris[i].push_back(cur_tris); + verts[i].push_back(cur_verts); + submeshes[i].push_back(cur_submeshes); + } + } + } + + if (mMaxTriangleLimit == 0) + { + mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH]; + } + + 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() && !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 && !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) && !mHasDegenerate;) + { + U16 index_a = face.mIndices[k + 0]; + U16 index_b = face.mIndices[k + 1]; + U16 index_c = face.mIndices[k + 2]; + + 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 + { + LL_DEBUGS("MeshValidation") << "Empty placeholder triangle (3 identical index 0 verts) ignored" << LL_ENDL; + } + else + { + 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"); + + S32 upload_status[LLModel::LOD_HIGH + 1]; + + mModelNoErrors = true; + + const U32 lod_high = LLModel::LOD_HIGH; + U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]); + + for (S32 lod = 0; lod <= lod_high; ++lod) + { + upload_status[lod] = 0; + + std::string message = "mesh_status_good"; + + if (total_tris[lod] > 0) + { + mFMP->childSetValue(lod_triangles_name[lod], llformat("%d", total_tris[lod])); + mFMP->childSetValue(lod_vertices_name[lod], llformat("%d", total_verts[lod])); + } + else + { + if (lod == lod_high) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + else + { + for (S32 i = lod - 1; i >= 0; --i) + { + if (total_tris[i] > 0) + { + upload_status[lod] = 2; + message = "mesh_status_missing_lod"; + } + } + } + + mFMP->childSetValue(lod_triangles_name[lod], mesh_status_na); + mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na); + } + + if (lod != lod_high) + { + if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) + { //number of submeshes is different + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + } + else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count) + {//number of submodels is different, not all faces are matched correctly. + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + // Note: Submodels in instance were loaded from higher LOD and as result face count + // returns same value and total_submeshes[lod] is identical to high_lod one. + } + else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) + { //number of meshes is different + message = "mesh_status_mesh_mismatch"; + upload_status[lod] = 2; + } + else if (!verts[lod].empty()) + { + S32 sum_verts_higher_lod = 0; + S32 sum_verts_this_lod = 0; + for (U32 i = 0; i < verts[lod].size(); ++i) + { + sum_verts_higher_lod += ((i < verts[lod + 1].size()) ? verts[lod + 1][i] : 0); + sum_verts_this_lod += verts[lod][i]; + } + + if ((sum_verts_higher_lod > 0) && + (sum_verts_this_lod > sum_verts_higher_lod)) + { + //too many vertices in this lod + message = "mesh_status_too_many_vertices"; + upload_status[lod] = 1; + } + } + } + + LLIconCtrl* icon = mFMP->getChild<LLIconCtrl>(lod_icon_name[lod]); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(true); + icon->setImage(img); + + if (upload_status[lod] >= 2) + { + mModelNoErrors = false; + } + + if (lod == mPreviewLOD) + { + mFMP->childSetValue("lod_status_message_text", mFMP->getString(message)); + icon = mFMP->getChild<LLIconCtrl>("lod_status_message_icon"); + icon->setImage(img); + } + + updateLodControls(lod); + } + + + //warn if hulls have more than 256 points in them + BOOL physExceededVertexLimit = FALSE; + for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + { + LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; + + if (mdl) + { + for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) + { + if (mdl->mPhysics.mHull[j].size() > 256) + { + physExceededVertexLimit = TRUE; + LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; + break; + } + } + } + } + + if (physExceededVertexLimit) + { + 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) + { + mModelNoErrors = false; + LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; + } + + bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); + bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); + + if (uploadingSkin) + { + if (uploadingJointPositions && !isRigValidForJointPositionUpload()) + { + mModelNoErrors = false; + LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; + } + } + + if (mModelNoErrors && mModelLoader) + { + if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + { + // Some textures are still loading, prevent upload until they are done + mModelNoErrors = false; + } + } + + if (!mModelNoErrors || mHasDegenerate) + { + mFMP->childDisable("ok_btn"); + mFMP->childDisable("calculate_btn"); + } + else + { + mFMP->childEnable("ok_btn"); + mFMP->childEnable("calculate_btn"); + } + + if (mModelNoErrors && mLodsWithParsingError.empty()) + { + mFMP->childEnable("calculate_btn"); + } + else + { + mFMP->childDisable("calculate_btn"); + } + + //add up physics triangles etc + S32 phys_tris = 0; + S32 phys_hulls = 0; + S32 phys_points = 0; + + //get the triangle count for the whole scene + for (LLModelLoader::scene::iterator iter = mScene[LLModel::LOD_PHYSICS].begin(), endIter = mScene[LLModel::LOD_PHYSICS].end(); iter != endIter; ++iter) + { + for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) + { + LLModel* model = instance->mModel; + if (model) + { + S32 cur_submeshes = model->getNumVolumeFaces(); + + LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull; + + if (!decomp.empty()) + { + phys_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + phys_points += decomp[i].size(); + } + } + else + { //choose physics shape OR decomposition, can't use both + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = model->getVolumeFace(j); + phys_tris += face.mNumIndices / 3; + } + } + } + } + } + + if (phys_tris > 0) + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", llformat("%d", phys_tris)); + } + else + { + mFMP->childSetTextArg("physics_triangles", "[TRIANGLES]", mesh_status_na); + } + + if (phys_hulls > 0) + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", llformat("%d", phys_hulls)); + mFMP->childSetTextArg("physics_points", "[POINTS]", llformat("%d", phys_points)); + } + else + { + mFMP->childSetTextArg("physics_hulls", "[HULLS]", mesh_status_na); + mFMP->childSetTextArg("physics_points", "[POINTS]", mesh_status_na); + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + if (phys_tris > 0 || phys_hulls > 0) + { + if (!fmp->isViewOptionEnabled("show_physics")) + { + fmp->enableViewOption("show_physics"); + mViewOption["show_physics"] = true; + fmp->childSetValue("show_physics", true); + } + } + else + { + fmp->disableViewOption("show_physics"); + mViewOption["show_physics"] = false; + fmp->childSetValue("show_physics", false); + + } + + //bool use_hull = fmp->childGetValue("physics_use_hull").asBoolean(); + + //fmp->childSetEnabled("physics_optimize", !use_hull); + + bool enable = (phys_tris > 0 || phys_hulls > 0) && fmp->mCurRequest.empty(); + //enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean(); + + //enable/disable "analysis" UI + LLPanel* panel = fmp->getChild<LLPanel>("physics analysis"); + LLView* child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + enable = phys_hulls > 0 && fmp->mCurRequest.empty(); + //enable/disable "simplification" UI + panel = fmp->getChild<LLPanel>("physics simplification"); + child = panel->getFirstChild(); + while (child) + { + child->setEnabled(enable); + child = panel->findNextSibling(child); + } + + if (fmp->mCurRequest.empty()) + { + fmp->childSetVisible("Simplify", true); + fmp->childSetVisible("simplify_cancel", false); + fmp->childSetVisible("Decompose", true); + fmp->childSetVisible("decompose_cancel", false); + + if (phys_hulls > 0) + { + fmp->childEnable("Simplify"); + } + + if (phys_tris || phys_hulls > 0) + { + fmp->childEnable("Decompose"); + } + } + else + { + fmp->childEnable("simplify_cancel"); + fmp->childEnable("decompose_cancel"); + } + } + + + LLCtrlSelectionInterface* iface = fmp->childGetSelectionInterface("physics_lod_combo"); + S32 which_mode = 0; + S32 file_mode = 1; + if (iface) + { + which_mode = iface->getFirstSelectedIndex(); + file_mode = iface->getItemCount() - 1; + } + + if (which_mode == file_mode) + { + mFMP->childEnable("physics_file"); + mFMP->childEnable("physics_browse"); + } + else + { + mFMP->childDisable("physics_file"); + mFMP->childDisable("physics_browse"); + } + + LLSpinCtrl* crease = mFMP->getChild<LLSpinCtrl>("crease_angle"); + + if (mRequestedCreaseAngle[mPreviewLOD] == -1.f) + { + mFMP->childSetColor("crease_label", LLColor4::grey); + crease->forceSetValue(75.f); + } + else + { + mFMP->childSetColor("crease_label", LLColor4::white); + crease->forceSetValue(mRequestedCreaseAngle[mPreviewLOD]); + } + + mModelUpdatedSignal(true); + +} + +void LLModelPreview::updateLodControls(S32 lod) +{ + if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::LOD_HIGH) + { + 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; + } + + const char* lod_controls[] = + { + "lod_mode_", + "lod_triangle_limit_", + "lod_error_threshold_" + }; + const U32 num_lod_controls = sizeof(lod_controls) / sizeof(char*); + + const char* file_controls[] = + { + "lod_browse_", + "lod_file_", + }; + const U32 num_file_controls = sizeof(file_controls) / sizeof(char*); + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (!fmp) return; + + LLComboBox* lod_combo = mFMP->findChild<LLComboBox>("lod_source_" + lod_name[lod]); + if (!lod_combo) return; + + S32 lod_mode = lod_combo->getCurrentIndex(); + if (lod_mode == LOD_FROM_FILE) // LoD from file + { + fmp->mLODMode[lod] = 0; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childSetVisible(file_controls[i] + lod_name[lod], true); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); + } + } + else if (lod_mode == USE_LOD_ABOVE) // use LoD above + { + fmp->mLODMode[lod] = 2; + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->childSetVisible(file_controls[i] + lod_name[lod], false); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->childSetVisible(lod_controls[i] + lod_name[lod], false); + } + + if (lod < LLModel::LOD_HIGH) + { + mModel[lod] = mModel[lod + 1]; + mScene[lod] = mScene[lod + 1]; + mVertexBuffer[lod].clear(); + + // Also update lower LoD + if (lod > LLModel::LOD_IMPOSTOR) + { + updateLodControls(lod - 1); + } + } + } + else // auto generate, the default case for all LoDs except High + { + fmp->mLODMode[lod] = 1; + + //don't actually regenerate lod when refreshing UI + mLODFrozen = true; + + for (U32 i = 0; i < num_file_controls; ++i) + { + mFMP->getChildView(file_controls[i] + lod_name[lod])->setVisible(false); + } + + for (U32 i = 0; i < num_lod_controls; ++i) + { + mFMP->getChildView(lod_controls[i] + lod_name[lod])->setVisible(true); + } + + + LLSpinCtrl* threshold = mFMP->getChild<LLSpinCtrl>("lod_error_threshold_" + lod_name[lod]); + LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod]); + + limit->setMaxValue(mMaxTriangleLimit); + limit->forceSetValue(mRequestedTriangleCount[lod]); + + threshold->forceSetValue(mRequestedErrorThreshold[lod]); + + mFMP->getChild<LLComboBox>("lod_mode_" + lod_name[lod])->selectNthItem(mRequestedLoDMode[lod]); + + if (mRequestedLoDMode[lod] == 0) + { + limit->setVisible(true); + threshold->setVisible(false); + + limit->setMaxValue(mMaxTriangleLimit); + limit->setIncrement(mMaxTriangleLimit / 32); + } + else + { + limit->setVisible(false); + threshold->setVisible(true); + } + + mLODFrozen = false; + } +} + +void LLModelPreview::setPreviewTarget(F32 distance) +{ + mCameraDistance = distance; + mCameraZoom = 1.f; + mCameraPitch = 0.f; + mCameraYaw = 0.f; + mCameraOffset.clearVec(); +} + +void LLModelPreview::clearBuffers() +{ + for (U32 i = 0; i < 6; i++) + { + mVertexBuffer[i].clear(); + } +} + +void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) +{ + U32 tri_count = 0; + U32 vertex_count = 0; + U32 mesh_count = 0; + + + LLModelLoader::model_list* model = NULL; + + if (lod < 0 || lod > 4) + { + model = &mBaseModel; + lod = 5; + } + else + { + model = &(mModel[lod]); + } + + if (!mVertexBuffer[lod].empty()) + { + mVertexBuffer[lod].clear(); + } + + mVertexBuffer[lod].clear(); + + LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); + + for (LLModelLoader::model_list::iterator iter = model->begin(); iter != model->end(); ++iter) + { + LLModel* mdl = *iter; + if (!mdl) + { + continue; + } + + LLModel* base_mdl = *base_iter; + base_iter++; + + S32 num_faces = mdl->getNumVolumeFaces(); + for (S32 i = 0; i < num_faces; ++i) + { + const LLVolumeFace &vf = mdl->getVolumeFace(i); + U32 num_vertices = vf.mNumVertices; + U32 num_indices = vf.mNumIndices; + + if (!num_vertices || !num_indices) + { + continue; + } + + LLVertexBuffer* vb = NULL; + + bool skinned = include_skin_weights && !mdl->mSkinWeights.empty(); + + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + if (skinned) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + vb = new LLVertexBuffer(mask, 0); + + 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 + 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; + LLStrider<LLVector3> normal_strider; + LLStrider<LLVector2> tc_strider; + LLStrider<U16> index_strider; + LLStrider<LLVector4> weights_strider; + + vb->getVertexStrider(vertex_strider); + vb->getIndexStrider(index_strider); + + if (skinned) + { + vb->getWeight4Strider(weights_strider); + } + + LLVector4a::memcpyNonAliased16((F32*)vertex_strider.get(), (F32*)vf.mPositions, num_vertices * 4 * sizeof(F32)); + + if (vf.mTexCoords) + { + vb->getTexCoord0Strider(tc_strider); + S32 tex_size = (num_vertices * 2 * sizeof(F32) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)tc_strider.get(), (F32*)vf.mTexCoords, tex_size); + } + + if (vf.mNormals) + { + vb->getNormalStrider(normal_strider); + LLVector4a::memcpyNonAliased16((F32*)normal_strider.get(), (F32*)vf.mNormals, num_vertices * 4 * sizeof(F32)); + } + + if (skinned) + { + for (U32 i = 0; i < num_vertices; i++) + { + //find closest weight to vf.mVertices[i].mPosition + LLVector3 pos(vf.mPositions[i].getF32ptr()); + + const LLModel::weight_list& weight_list = base_mdl->getJointInfluences(pos); + llassert(weight_list.size()>0 && weight_list.size() <= 4); // LLModel::loadModel() should guarantee this + + LLVector4 w(0, 0, 0, 0); + + for (U32 i = 0; i < weight_list.size(); ++i) + { + F32 wght = llclamp(weight_list[i].mWeight, 0.001f, 0.999f); + F32 joint = (F32)weight_list[i].mJointIdx; + w.mV[i] = joint + wght; + llassert(w.mV[i] - (S32)w.mV[i]>0.0f); // because weights are non-zero, and range of wt values + //should not cause floating point precision issues. + } + + *(weights_strider++) = w; + } + } + + // build indices + for (U32 i = 0; i < num_indices; i++) + { + *(index_strider++) = vf.mIndices[i]; + } + + mVertexBuffer[lod][mdl].push_back(vb); + + vertex_count += num_vertices; + tri_count += num_indices / 3; + ++mesh_count; + + } + } +} + +void LLModelPreview::update() +{ + if (mGenLOD) + { + bool subscribe_for_generation = mLodsQuery.empty(); + mGenLOD = false; + mDirty = true; + mLodsQuery.clear(); + + for (S32 lod = LLModel::LOD_HIGH; lod >= 0; --lod) + { + // adding all lods into query for generation + mLodsQuery.push_back(lod); + } + + if (subscribe_for_generation) + { + doOnIdleRepeating(lodQueryCallback); + } + } + + if (mDirty && mLodsQuery.empty()) + { + mDirty = false; + mResourceCost = calcResourceCost(); + refresh(); + updateStatusMessages(); + } +} + +//----------------------------------------------------------------------------- +// createPreviewAvatar +//----------------------------------------------------------------------------- +void LLModelPreview::createPreviewAvatar(void) +{ + mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); + if (mPreviewAvatar) + { + mPreviewAvatar->createDrawable(&gPipeline); + mPreviewAvatar->mSpecialRenderMode = 1; + mPreviewAvatar->startMotion(ANIM_AGENT_STAND); + mPreviewAvatar->hideSkirt(); + } + else + { + LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; + } +} + +//static +U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) +{ + U32 root_models = 0; + model_list::iterator model_iter = models.begin(); + while (model_iter != models.end()) + { + LLModel* mdl = *model_iter; + if (mdl && mdl->mSubmodelID == 0) + { + root_models++; + } + model_iter++; + } + return root_models; +} + +void LLModelPreview::loadedCallback( + LLModelLoader::scene& scene, + LLModelLoader::model_list& model_list, + S32 lod, + void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) + { + // 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) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview) + { + pPreview->setLoadState(state); + } +} + +LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview) + { + return pPreview->getPreviewAvatar()->getJoint(str); + } + return NULL; +} + +U32 LLModelPreview::loadTextures(LLImportMaterial& material, void* opaque) +{ + (void)opaque; + + if (material.mDiffuseMapFilename.size()) + { + material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; + LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); + + tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); + tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); + tex->forceToSaveRawImage(0, F32_MAX); + material.setDiffuseMap(tex->getID()); // record tex ID + return 1; + } + + material.mOpaqueData = NULL; + return 0; +} + +void LLModelPreview::addEmptyFace(LLModel* pTarget) +{ + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); + + buff->allocateBuffer(1, 3, true); + memset((U8*)buff->getMappedData(), 0, buff->getSize()); + memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize()); + + buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0); + + LLStrider<LLVector3> pos; + LLStrider<LLVector3> norm; + LLStrider<LLVector2> tc; + LLStrider<U16> index; + + buff->getVertexStrider(pos); + + if (type_mask & LLVertexBuffer::MAP_NORMAL) + { + buff->getNormalStrider(norm); + } + if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + buff->getTexCoord0Strider(tc); + } + + buff->getIndexStrider(index); + + //resize face array + int faceCnt = pTarget->getNumVolumeFaces(); + 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(); + + LLMutexLock lock(this); + mNeedsUpdate = FALSE; + + bool use_shaders = LLGLSLShader::sNoFixedFunction; + + bool edges = mViewOption["show_edges"]; + bool joint_overrides = mViewOption["show_joint_overrides"]; + bool joint_positions = mViewOption["show_joint_positions"]; + bool skin_weight = mViewOption["show_skin_weight"]; + bool textures = mViewOption["show_textures"]; + bool physics = mViewOption["show_physics"]; + + // Extra configurability, to be exposed later as controls? + static LLCachedControl<LLColor4> canvas_col(gSavedSettings, "MeshPreviewCanvasColor"); + static LLCachedControl<LLColor4> edge_col(gSavedSettings, "MeshPreviewEdgeColor"); + static LLCachedControl<LLColor4> base_col(gSavedSettings, "MeshPreviewBaseColor"); + static LLCachedControl<LLColor3> brightness(gSavedSettings, "MeshPreviewBrightnessColor"); + static LLCachedControl<F32> edge_width(gSavedSettings, "MeshPreviewEdgeWidth"); + static LLCachedControl<LLColor4> phys_edge_col(gSavedSettings, "MeshPreviewPhysicsEdgeColor"); + static LLCachedControl<LLColor4> phys_fill_col(gSavedSettings, "MeshPreviewPhysicsFillColor"); + static LLCachedControl<F32> phys_edge_width(gSavedSettings, "MeshPreviewPhysicsEdgeWidth"); + static LLCachedControl<LLColor4> deg_edge_col(gSavedSettings, "MeshPreviewDegenerateEdgeColor"); + static LLCachedControl<LLColor4> deg_fill_col(gSavedSettings, "MeshPreviewDegenerateFillColor"); + static LLCachedControl<F32> deg_edge_width(gSavedSettings, "MeshPreviewDegenerateEdgeWidth"); + static LLCachedControl<F32> deg_point_size(gSavedSettings, "MeshPreviewDegeneratePointSize"); + + S32 width = getWidth(); + S32 height = getHeight(); + + LLGLSUIDefault def; // GL_BLEND, GL_ALPHA_TEST, GL_CULL_FACE, depth test + LLGLDisable no_blend(GL_BLEND); + LLGLDepthTest depth(GL_FALSE); // SL-12781 disable z-buffer to render background color + LLGLDisable fog(GL_FOG); + + { + if (use_shaders) + { + gUIProgram.bind(); + } + //clear background to grey + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + gGL.color4fv(static_cast<LLColor4>(canvas_col).mV); + gl_rect_2d_simple(width, height); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + if (use_shaders) + { + gUIProgram.unbind(); + } + } + + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + + bool has_skin_weights = false; + bool upload_skin = mFMP->childGetValue("upload_skin").asBoolean(); + bool upload_joints = mFMP->childGetValue("upload_joints").asBoolean(); + + if (upload_joints != mLastJointUpdate) + { + mLastJointUpdate = upload_joints; + } + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].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; + model->mPelvisOffset = mPelvisZOffset; + if (!model->mSkinWeights.empty()) + { + has_skin_weights = true; + } + } + } + + if (has_skin_weights && lodsReady()) + { //model has skin weights, enable view options for skin weights and joint positions + 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 + { + mFMP->childDisable("upload_skin"); + if (fmp) + { + mViewOption["show_skin_weight"] = false; + fmp->disableViewOption("show_skin_weight"); + fmp->disableViewOption("show_joint_overrides"); + fmp->disableViewOption("show_joint_positions"); + + skin_weight = false; + mFMP->childSetValue("show_skin_weight", false); + fmp->setViewOptionEnabled("show_skin_weight", skin_weight); + } + } + + if (upload_skin && !has_skin_weights) + { //can't upload skin weights if model has no skin weights + mFMP->childSetValue("upload_skin", false); + upload_skin = false; + } + + if (!upload_skin && upload_joints) + { //can't upload joints if not uploading skin weights + mFMP->childSetValue("upload_joints", false); + upload_joints = false; + } + + 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 + if (isRigValidForJointPositionUpload()) + { + mFMP->childSetEnabled("upload_joints", upload_skin); + } + + F32 explode = mFMP->childGetValue("physics_explode").asReal(); + + LLGLDepthTest gls_depth(GL_TRUE); // SL-12781 re-enable z-buffer for 3D model preview + + LLRect preview_rect; + + preview_rect = mFMP->getChildView("preview_panel")->getRect(); + + F32 aspect = (F32)preview_rect.getWidth() / preview_rect.getHeight(); + + LLViewerCamera::getInstance()->setAspect(aspect); + + LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); + + LLVector3 offset = mCameraOffset; + LLVector3 target_pos = mPreviewTarget + offset; + + F32 z_near = 0.001f; + F32 z_far = mCameraDistance*10.0f + mPreviewScale.magVec() + mCameraOffset.magVec(); + + if (skin_weight) + { + target_pos = getPreviewAvatar()->getPositionAgent() + offset; + z_near = 0.01f; + z_far = 1024.f; + + //render avatar previews every frame + refresh(); + } + + if (use_shaders) + { + gObjectPreviewProgram.bind(); + } + + gGL.loadIdentity(); + gPipeline.enableLightsPreview(); + + LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * + 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(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + + z_near = llclamp(z_far * 0.001f, 0.001f, 0.1f); + + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, width, height, FALSE, z_near, z_far); + + stop_glerror(); + + gGL.pushMatrix(); + gGL.color4fv(edge_col().mV); + + const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + + LLGLEnable normalize(GL_NORMALIZE); + + if (!mBaseModel.empty() && mVertexBuffer[5].empty()) + { + genBuffers(-1, skin_weight); + //genBuffers(3); + //genLODs(); + } + + if (!mModel[mPreviewLOD].empty()) + { + mFMP->childEnable("reset_btn"); + + bool regen = mVertexBuffer[mPreviewLOD].empty(); + if (!regen) + { + const std::vector<LLPointer<LLVertexBuffer> >& vb_vec = mVertexBuffer[mPreviewLOD].begin()->second; + if (!vb_vec.empty()) + { + const LLVertexBuffer* buff = vb_vec[0]; + regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; + } + else + { + LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + regen = TRUE; + } + } + + if (regen) + { + genBuffers(mPreviewLOD, skin_weight); + } + + if (!skin_weight) + { + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[mPreviewLOD]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + gGL.multMatrix((GLfloat*)mat.mMatrix); + + + U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); + for (U32 i = 0; i < num_models; ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + + if (textures) + { + int materialCnt = instance.mModel->mMaterialList.size(); + if (i < materialCnt) + { + const std::string& binding = instance.mModel->mMaterialList[i]; + const LLImportMaterial& material = instance.mMaterial[binding]; + + gGL.diffuseColor4fv(material.mDiffuseColor.mV); + + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) + { + mTextureSet.insert(tex); + } + } + } + else + { + 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.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV); + if (edges) + { + 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); + glLineWidth(1.f); + } + } + gGL.popMatrix(); + } + + if (physics) + { + glClear(GL_DEPTH_BUFFER_BIT); + + for (U32 pass = 0; pass < 2; pass++) + { + if (pass == 0) + { //depth only pass + gGL.setColorMask(false, false); + } + else + { + gGL.setColorMask(true, true); + } + + //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) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + gGL.multMatrix((GLfloat*)mat.mMatrix); + + + bool render_mesh = true; + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + LLModel::Decomposition& physics = model->mPhysics; + + if (!physics.mHull.empty()) + { + render_mesh = false; + + if (physics.mMesh.empty()) + { //build vertex buffer for physics mesh + gMeshRepo.buildPhysicsMesh(physics); + } + + if (!physics.mMesh.empty()) + { //render hull instead of mesh + for (U32 i = 0; i < physics.mMesh.size(); ++i) + { + if (explode > 0.f) + { + gGL.pushMatrix(); + + LLVector3 offset = model->mHullCenter[i] - model->mCenterOfHullCenters; + offset *= explode; + + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + } + + 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)); + } + + 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 (render_mesh) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + + 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.diffuseColor4fv(phys_fill_col().mV); + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); + + 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); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glLineWidth(1.f); + } + } + } + gGL.popMatrix(); + } + + // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] + if (pass > 0 && mHasDegenerate) + { + 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) + { + LLModelInstance& instance = *iter; + + LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; + + if (!model) + { + continue; + } + + gGL.pushMatrix(); + LLMatrix4 mat = instance.mTransform; + + gGL.multMatrix((GLfloat*)mat.mMatrix); + + + LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; + if (decomp) + { + LLMutexLock(decomp->mMutex); + + LLModel::Decomposition& physics = model->mPhysics; + + if (physics.mHull.empty()) + { + if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + + U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); + for (U32 v = 0; v < num_models; ++v) + { + 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); + + LLVector4a v1, v2, v3; + for (U32 indices_offset = 0; indices_offset < buffer->getNumIndices(); indices_offset += 3) + { + v1.setMul(pos[*idx++], scale); + v2.setMul(pos[*idx++], scale); + v3.setMul(pos[*idx++], scale); + + if (ll_is_degenerate(v1, v2, v3)) + { + 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(); + } + 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(camera_distance, 0.f, 0.f) + offset) * av_rot), // camera + LLVector3::z_axis, // up + target_pos); // point of interest + + for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].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; + + 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]; + + const LLVolumeFace& face = model->getVolumeFace(i); + + LLStrider<LLVector3> position; + buffer->getVertexStrider(position); + + LLStrider<LLVector4> weight; + buffer->getWeight4Strider(weight); + + //quick 'n dirty software vertex skinning + + //build matrix palette + + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, + skin, getPreviewAvatar()); + + LLMatrix4a bind_shape_matrix; + bind_shape_matrix.loadu(skin->mBindShapeMatrix); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); + for (U32 j = 0; j < buffer->getNumVerts(); ++j) + { + LLMatrix4a final_mat; + F32 *wptr = weight[j].mV; + LLSkinningUtil::getPerVertexSkinMatrix(wptr, mat, true, final_mat, max_joints); + + //VECTORIZE THIS + LLVector4a& v = face.mPositions[j]; + + LLVector4a t; + LLVector4a dst; + bind_shape_matrix.affineTransform(v, t); + final_mat.affineTransform(t, dst); + + position[j][0] = dst[0]; + position[j][1] = dst[1]; + position[j][2] = dst[2]; + } + + llassert(model->mMaterialList.size() > i); + const std::string& binding = instance.mModel->mMaterialList[i]; + const LLImportMaterial& material = instance.mMaterial[binding]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + gGL.diffuseColor4fv(material.mDiffuseColor.mV); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) + { + mTextureSet.insert(tex); + } + + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); + + if (edges) + { + 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); + glLineWidth(1.f); + } + } + } + } + } + + if (joint_positions) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + gDebugProgram.bind(); + } + getPreviewAvatar()->renderCollisionVolumes(); + 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(); + } + } + } + + if (use_shaders) + { + gObjectPreviewProgram.unbind(); + } + + gGL.popMatrix(); + + return TRUE; +} + +//----------------------------------------------------------------------------- +// refresh() +//----------------------------------------------------------------------------- +void LLModelPreview::refresh() +{ + mNeedsUpdate = TRUE; +} + +//----------------------------------------------------------------------------- +// rotate() +//----------------------------------------------------------------------------- +void LLModelPreview::rotate(F32 yaw_radians, F32 pitch_radians) +{ + mCameraYaw = mCameraYaw + yaw_radians; + + mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f); +} + +//----------------------------------------------------------------------------- +// zoom() +//----------------------------------------------------------------------------- +void LLModelPreview::zoom(F32 zoom_amt) +{ + F32 new_zoom = mCameraZoom + zoom_amt; + // 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) +{ + 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) +{ + lod = llclamp(lod, 0, (S32)LLModel::LOD_HIGH); + + if (lod != mPreviewLOD) + { + mPreviewLOD = lod; + + LLComboBox* combo_box = mFMP->getChild<LLComboBox>("preview_lod_combo"); + 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]); + + LLColor4 highlight_color = LLUIColorTable::instance().getColor("MeshImportTableHighlightColor"); + LLColor4 normal_color = LLUIColorTable::instance().getColor("MeshImportTableNormalColor"); + + for (S32 i = 0; i <= LLModel::LOD_HIGH; ++i) + { + const LLColor4& color = (i == lod) ? highlight_color : normal_color; + + mFMP->childSetColor(lod_status_name[i], color); + mFMP->childSetColor(lod_label_name[i], color); + 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(); +} + +//static +void LLModelPreview::textureLoadedCallback( + BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* src_aux, + S32 discard_level, + BOOL final, + void* userdata) +{ + LLModelPreview* preview = (LLModelPreview*)userdata; + preview->refresh(); + + if (final && preview->mModelLoader) + { + if (preview->mModelLoader->mNumOfFetchingTextures > 0) + { + preview->mModelLoader->mNumOfFetchingTextures--; + } + } +} + +// static +bool LLModelPreview::lodQueryCallback() +{ + // not the best solution, but model preview belongs to floater + // so it is an easy way to check that preview still exists. + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp && fmp->mModelPreview) + { + LLModelPreview* preview = fmp->mModelPreview; + if (preview->mLodsQuery.size() > 0) + { + S32 lod = preview->mLodsQuery.back(); + preview->mLodsQuery.pop_back(); + preview->genLODs(lod); + + // return false to continue cycle + return false; + } + } + // nothing to process + return true; +} + +void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) +{ + if (!mLODFrozen) + { + genLODs(lod, 3, enforce_tri_limit); + refresh(); + } +} + diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h new file mode 100644 index 0000000000..7a7b8615f9 --- /dev/null +++ b/indra/newview/llmodelpreview.h @@ -0,0 +1,308 @@ +/** + * @file llmodelpreview.h + * @brief LLModelPreview class definition, class + * responsible for model preview inside LLFloaterModelPreview + * + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2020, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMODELPREVIEW_H +#define LL_LLMODELPREVIEW_H + +#include "lldynamictexture.h" +#include "llfloatermodelpreview.h" +#include "llmeshrepository.h" +#include "llmodel.h" + +class LLJoint; +class LLVOAvatar; +class LLTextBox; +class LLVertexBuffer; +class DAE; +class daeElement; +class domProfile_COMMON; +class domInstance_geometry; +class domNode; +class domTranslate; +class domController; +class domSkin; +class domMesh; + +// const strings needed by classes that use model preivew +static const std::string lod_name[NUM_LOD + 1] = +{ + "lowest", + "low", + "medium", + "high", + "I went off the end of the lod_name array. Me so smart." +}; + +static const std::string lod_triangles_name[NUM_LOD + 1] = +{ + "lowest_triangles", + "low_triangles", + "medium_triangles", + "high_triangles", + "I went off the end of the lod_triangles_name array. Me so smart." +}; + +static const std::string lod_vertices_name[NUM_LOD + 1] = +{ + "lowest_vertices", + "low_vertices", + "medium_vertices", + "high_vertices", + "I went off the end of the lod_vertices_name array. Me so smart." +}; + +static const std::string lod_status_name[NUM_LOD + 1] = +{ + "lowest_status", + "low_status", + "medium_status", + "high_status", + "I went off the end of the lod_status_name array. Me so smart." +}; + +static const std::string lod_icon_name[NUM_LOD + 1] = +{ + "status_icon_lowest", + "status_icon_low", + "status_icon_medium", + "status_icon_high", + "I went off the end of the lod_status_name array. Me so smart." +}; + +static const std::string lod_status_image[NUM_LOD + 1] = +{ + "ModelImport_Status_Good", + "ModelImport_Status_Warning", + "ModelImport_Status_Error", + "I went off the end of the lod_status_image array. Me so smart." +}; + +static const std::string lod_label_name[NUM_LOD + 1] = +{ + "lowest_label", + "low_label", + "medium_label", + "high_label", + "I went off the end of the lod_label_name array. Me so smart." +}; + +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; + +public: + + typedef enum + { + LOD_FROM_FILE = 0, + GENERATE, + USE_LOD_ABOVE, + } eLoDMode; + +public: + // Todo: model preview shouldn't need floater dependency, it + // should just expose data to floater, not control flaoter like it does + LLModelPreview(S32 width, S32 height, LLFloater* fmp); + virtual ~LLModelPreview(); + + void resetPreviewTarget(); + void setPreviewTarget(F32 distance); + void setTexture(U32 name) { mTextureName = name; } + + void setPhysicsFromLOD(S32 lod); + BOOL render(); + void update(); + void genBuffers(S32 lod, bool skinned); + void clearBuffers(); + void refresh(); + void rotate(F32 yaw_radians, F32 pitch_radians); + void zoom(F32 zoom_amt); + void pan(F32 right, F32 up); + virtual BOOL needsRender() { return mNeedsUpdate; } + void setPreviewLOD(S32 lod); + void clearModel(S32 lod); + void getJointAliases(JointMap& joint_map); + void loadModel(std::string filename, S32 lod, bool force_disable_slm = false); + void loadModelCallback(S32 lod); + bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } + void queryLODs() { mGenLOD = true; }; + void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); + void generateNormals(); + void restoreNormals(); + U32 calcResourceCost(); + void rebuildUploadData(); + void saveUploadData(bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); + void saveUploadData(const std::string& filename, bool save_skinweights, bool save_joint_positions, bool lock_scale_if_joint_position); + void clearIncompatible(S32 lod); + void updateStatusMessages(); + void updateLodControls(S32 lod); + void clearGLODGroup(); + void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void addEmptyFace(LLModel* pTarget); + + const bool getModelPivot(void) const { return mHasPivot; } + void setHasPivot(bool val) { mHasPivot = val; } + void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; } + + //Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions + //Accessors for joint position upload friendly rigs + const bool isRigValidForJointPositionUpload(void) const { return mRigValidJointUpload; } + void setRigValidForJointPositionUpload(bool rigValid) { mRigValidJointUpload = rigValid; } + + //Accessors for the legacy rigs + 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(); + + boost::signals2::connection setDetailsCallback(const details_signal_t::slot_type& cb){ return mDetailsSignal.connect(cb); } + boost::signals2::connection setModelLoadedCallback(const model_loaded_signal_t::slot_type& cb){ return mModelLoadedSignal.connect(cb); } + boost::signals2::connection setModelUpdatedCallback(const model_updated_signal_t::slot_type& cb){ return mModelUpdatedSignal.connect(cb); } + + void setLoadState(U32 state) { mLoadState = state; } + U32 getLoadState() { return mLoadState; } + + static bool sIgnoreLoadedCallback; + std::vector<S32> mLodsQuery; + std::vector<S32> mLodsWithParsingError; + bool mHasDegenerate; + +protected: + + static void loadedCallback(LLModelLoader::scene& scene, LLModelLoader::model_list& model_list, S32 lod, void* opaque); + static void stateChangedCallback(U32 state, void* opaque); + + static LLJoint* lookupJointByName(const std::string&, void* opaque); + static U32 loadTextures(LLImportMaterial& material, void* opaque); + +private: + //Utility function for controller vertex compare + bool verifyCount(int expected, int result); + //Creates the dummy avatar for the preview window + void createPreviewAvatar(void); + //Accessor for the dummy avatar + LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; } + // Count amount of original models, excluding sub-models + static U32 countRootModels(LLModelLoader::model_list models); + +protected: + friend class LLModelLoader; + friend class LLFloaterModelPreview; + friend class LLFloaterModelPreview::DecompRequest; + friend class LLPhysicsDecomp; + + LLFloater* mFMP; + + BOOL mNeedsUpdate; + bool mDirty; + bool mGenLOD; + U32 mTextureName; + F32 mCameraDistance; + F32 mCameraYaw; + F32 mCameraPitch; + F32 mCameraZoom; + LLVector3 mCameraOffset; + LLVector3 mPreviewTarget; + LLVector3 mPreviewScale; + S32 mPreviewLOD; + S32 mPhysicsSearchLOD; + U32 mResourceCost; + std::string mLODFile[LLModel::NUM_LODS]; + bool mLoading; + U32 mLoadState; + bool mResetJoints; + bool mModelNoErrors; + + std::map<std::string, bool> mViewOption; + + //GLOD object parameters (must rebuild object if these change) + bool mLODFrozen; + F32 mBuildShareTolerance; + U32 mBuildQueueMode; + U32 mBuildOperator; + U32 mBuildBorderMode; + U32 mRequestedLoDMode[LLModel::NUM_LODS]; + S32 mRequestedTriangleCount[LLModel::NUM_LODS]; + F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; + U32 mRequestedBuildOperator[LLModel::NUM_LODS]; + U32 mRequestedQueueMode[LLModel::NUM_LODS]; + U32 mRequestedBorderMode[LLModel::NUM_LODS]; + F32 mRequestedShareTolerance[LLModel::NUM_LODS]; + F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; + + LLModelLoader* mModelLoader; + + LLModelLoader::scene mScene[LLModel::NUM_LODS]; + LLModelLoader::scene mBaseScene; + + LLModelLoader::model_list mModel[LLModel::NUM_LODS]; + LLModelLoader::model_list mBaseModel; + + typedef std::vector<LLVolumeFace> v_LLVolumeFace_t; + typedef std::vector<v_LLVolumeFace_t> vv_LLVolumeFace_t; + + vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS]; + vv_LLVolumeFace_t mBaseModelFacesCopy; + + U32 mGroup; + std::map<LLPointer<LLModel>, U32> mObject; + U32 mMaxTriangleLimit; + + LLMeshUploadThread::instance_list mUploadData; + std::set<LLViewerFetchedTexture * > mTextureSet; + + //map of vertex buffers to models (one vertex buffer in vector per face in model + std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS + 1]; + + details_signal_t mDetailsSignal; + model_loaded_signal_t mModelLoadedSignal; + model_updated_signal_t mModelUpdatedSignal; + + LLVector3 mModelPivot; + bool mHasPivot; + + float mPelvisZOffset; + + bool mRigValidJointUpload; + U32 mLegacyRigFlags; + + bool mLastJointUpdate; + + JointNameSet mJointsFromNode; + JointTransformMap mJointTransformMap; + + LLPointer<LLVOAvatar> mPreviewAvatar; + LLCachedControl<bool> mImporterDebug; +}; + +#endif // LL_LLMODELPREVIEW_H -- cgit v1.2.3 From 72ba7f1dad43306a761b35dc984734dae04c1c6d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 22 Apr 2020 20:55:57 +0300 Subject: SL-13077 remove floater specific variables from settings.xml --- indra/newview/app_settings/settings.xml | 193 -------------------------------- indra/newview/llfloatermodelpreview.cpp | 20 ++-- indra/newview/llmodelpreview.cpp | 70 ++++++------ indra/newview/llmodelpreview.h | 1 + 4 files changed, 41 insertions(+), 243 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c1a2c0ff7a..b2d1d2e589 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6661,188 +6661,6 @@ <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> <key>Comment</key> @@ -8094,17 +7912,6 @@ <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> diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 9c62680dde..5df3139d0d 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -41,8 +41,6 @@ #include "llbutton.h" #include "llcombobox.h" #include "llfocusmgr.h" -#include "llmatrix4a.h" -#include "llmenubutton.h" #include "llmeshrepository.h" #include "llnotificationsutil.h" #include "llsdutil_math.h" @@ -50,23 +48,17 @@ #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" -#include "llvector4a.h" #include "llviewerwindow.h" #include "pipeline.h" #include "llviewercontrol.h" -#include "llviewermenufile.h" +#include "llviewermenufile.h" //LLFilePickerThread #include "llstring.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llradiogroup.h" -#include "llsdserialize.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "lltabcontainer.h" -#include "lltoggleablemenu.h" #include "lltrans.h" -#include "llvfile.h" -#include "llvfs.h" #include "llcallbacklist.h" #include "llviewertexteditor.h" #include "llviewernetwork.h" @@ -88,6 +80,8 @@ const double RETAIN_COEFFICIENT = 100; // should be represented by Smooth combobox with only 10 values. // So this const is used as a size of Smooth combobox list. const S32 SMOOTH_VALUES_NUMBER = 10; +const S32 PREVIEW_RENDER_SIZE = 1024; +const F32 PREVIEW_CAMERA_DISTANCE = 16.f; class LLMeshFilePicker : public LLFilePickerThread { @@ -314,9 +308,9 @@ void LLFloaterModelPreview::initModelPreview() 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); - + S32 max_width = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenWidth); + S32 max_height = llmin(PREVIEW_RENDER_SIZE, (S32)gPipeline.mScreenHeight); + while ((tex_width << 1) < max_width) { tex_width <<= 1; @@ -327,7 +321,7 @@ void LLFloaterModelPreview::initModelPreview() } mModelPreview = new LLModelPreview(tex_width, tex_height, this); - mModelPreview->setPreviewTarget(16.f); + mModelPreview->setPreviewTarget(PREVIEW_CAMERA_DISTANCE); mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelPreview::setDetails, this, _1, _2, _3, _4, _5)); mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelPreview::modelUpdated, this, _1)); } diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 96af3b37d9..9260699985 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -26,17 +26,12 @@ #include "llviewerprecompiledheaders.h" +#include "llmodelpreview.h" + #include "llmodelloader.h" #include "lldaeloader.h" #include "llfloatermodelpreview.h" -#include "llmodelpreview.h" - -#include "llimagebmp.h" -#include "llimagetga.h" -#include "llimagejpeg.h" -#include "llimagepng.h" - #include "llagent.h" #include "llanimationstates.h" #include "llcallbacklist.h" @@ -76,6 +71,22 @@ bool LLModelPreview::sIgnoreLoadedCallback = false; +// Extra configurability, to be exposed later in xml (LLModelPreview probably +// should become UI control at some point or get split into preview control) +static const LLColor4 PREVIEW_CANVAS_COL(0.169f, 0.169f, 0.169f, 1.f); +static const LLColor4 PREVIEW_EDGE_COL(0.4f, 0.4f, 0.4f, 1.0); +static const LLColor4 PREVIEW_BASE_COL(1.f, 1.f, 1.f, 1.f); +static const LLColor3 PREVIEW_BRIGHTNESS(0.9f, 0.9f, 0.9f); +static const F32 PREVIEW_EDGE_WIDTH(1.f); +static const LLColor4 PREVIEW_PSYH_EDGE_COL(0.f, 0.25f, 0.5f, 0.25f); +static const LLColor4 PREVIEW_PSYH_FILL_COL(0.f, 0.5f, 1.0f, 0.5f); +static const F32 PREVIEW_PSYH_EDGE_WIDTH(1.f); +static const LLColor4 PREVIEW_DEG_EDGE_COL(1.f, 0.f, 0.f, 1.f); +static const LLColor4 PREVIEW_DEG_FILL_COL(1.f, 0.f, 0.f, 0.5f); +static const F32 PREVIEW_DEG_EDGE_WIDTH(3.f); +static const F32 PREVIEW_DEG_POINT_SIZE(8.f); +static const F32 PREVIEW_ZOOM_LIMIT(10.f); + const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; BOOL stop_gloderror() @@ -2677,20 +2688,6 @@ BOOL LLModelPreview::render() 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(); @@ -2714,7 +2711,7 @@ BOOL LLModelPreview::render() gGL.pushMatrix(); gGL.loadIdentity(); - gGL.color4fv(static_cast<LLColor4>(canvas_col).mV); + gGL.color4fv(PREVIEW_CANVAS_COL.mV); gl_rect_2d_simple(width, height); gGL.matrixMode(LLRender::MM_PROJECTION); @@ -2884,7 +2881,7 @@ BOOL LLModelPreview::render() stop_glerror(); gGL.pushMatrix(); - gGL.color4fv(edge_col().mV); + gGL.color4fv(PREVIEW_EDGE_COL.mV); const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -2969,15 +2966,15 @@ BOOL LLModelPreview::render() } else { - gGL.diffuseColor4fv(static_cast<LLColor4>(base_col).mV); + gGL.diffuseColor4fv(PREVIEW_BASE_COL.mV); } buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.diffuseColor4fv(static_cast<LLColor4>(edge_col).mV); + gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); if (edges) { - glLineWidth(edge_width); + glLineWidth(PREVIEW_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); @@ -3088,13 +3085,13 @@ BOOL LLModelPreview::render() LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.diffuseColor4fv(phys_fill_col().mV); + gGL.diffuseColor4fv(PREVIEW_PSYH_FILL_COL.mV); buffer->setBuffer(type_mask & buffer->getTypeMask()); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); - gGL.diffuseColor4fv(phys_edge_col().mV); - glLineWidth(phys_edge_width); + gGL.diffuseColor4fv(PREVIEW_PSYH_EDGE_COL.mV); + glLineWidth(PREVIEW_PSYH_EDGE_WIDTH); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0); @@ -3109,8 +3106,8 @@ BOOL LLModelPreview::render() // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] if (pass > 0 && mHasDegenerate) { - glLineWidth(deg_edge_width); - glPointSize(deg_point_size); + glLineWidth(PREVIEW_DEG_EDGE_WIDTH); + glPointSize(PREVIEW_DEG_POINT_SIZE); gPipeline.enableLightsFullbright(); //show degenerate triangles LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); @@ -3174,11 +3171,11 @@ BOOL LLModelPreview::render() if (ll_is_degenerate(v1, v2, v3)) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gGL.diffuseColor3fv(deg_edge_col().mV); + gGL.diffuseColor3fv(PREVIEW_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); + gGL.diffuseColor3fv(PREVIEW_DEG_FILL_COL.mV); buffer->drawRange(LLRender::TRIANGLES, 0, 2, 3, indices_offset); } } @@ -3326,8 +3323,8 @@ BOOL LLModelPreview::render() if (edges) { - gGL.diffuseColor4fv(edge_col().mV); - glLineWidth(edge_width); + gGL.diffuseColor4fv(PREVIEW_EDGE_COL.mV); + glLineWidth(PREVIEW_EDGE_WIDTH); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -3403,8 +3400,7 @@ void LLModelPreview::zoom(F32 zoom_amt) { F32 new_zoom = mCameraZoom + zoom_amt; // TODO: stop clamping in render - static LLCachedControl<F32> zoom_limit(gSavedSettings, "MeshPreviewZoomLimit"); - mCameraZoom = llclamp(new_zoom, 1.f, zoom_limit()); + mCameraZoom = llclamp(new_zoom, 1.f, PREVIEW_ZOOM_LIMIT); } void LLModelPreview::pan(F32 right, F32 up) diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 7a7b8615f9..4c03849d6b 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -31,6 +31,7 @@ #include "lldynamictexture.h" #include "llfloatermodelpreview.h" #include "llmeshrepository.h" +#include "llmodelloader.h" //NUM_LOD #include "llmodel.h" class LLJoint; -- cgit v1.2.3 From cac08f80a44139f9752523dca278eefde96a6a8c Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Thu, 23 Apr 2020 20:04:01 +0300 Subject: SL-13074 FIXED [Mesh Uploader] "The texture is empty" error is displayed after trying to upload the model with the texture from the non-English directory --- indra/newview/llmodelpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 9260699985..9e39d0cf51 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2619,7 +2619,7 @@ U32 LLModelPreview::loadTextures(LLImportMaterial& material, void* opaque) material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); - tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); + tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + LLURI::unescape(material.mDiffuseMapFilename), FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); tex->forceToSaveRawImage(0, F32_MAX); material.setDiffuseMap(tex->getID()); // record tex ID -- cgit v1.2.3 From c54e0e4f12dedff2d64354215fd7bcb68b09c7fd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 23 Apr 2020 19:33:47 +0300 Subject: SL-12678 Remove automatic retry of login --- indra/newview/lllogininstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 8a69acb8dc..873531ef22 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -62,7 +62,7 @@ #include <boost/scoped_ptr.hpp> #include <sstream> -const S32 LOGIN_MAX_RETRIES = 3; +const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login const F32 LOGIN_SRV_TIMEOUT_MIN = 10; const F32 LOGIN_SRV_TIMEOUT_MAX = 120; const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time -- cgit v1.2.3 From 9221c8a3f65aa14cad4fec03b7033ad800f6ba35 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 23 Apr 2020 19:34:14 +0300 Subject: SL-13080 Changes for joint listings in mesh uploader --- indra/llprimitive/lldaeloader.cpp | 6 ++ indra/newview/llfloatermodelpreview.cpp | 126 +++++++++++++++++++++++--------- indra/newview/llfloatermodelpreview.h | 5 +- indra/newview/llmodelpreview.cpp | 36 ++++++--- 4 files changed, 126 insertions(+), 47 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 139f48fef8..431443788c 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1470,6 +1470,12 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do } } + U32 bind_count = model->mSkinInfo.mAlternateBindMatrix.size(); + if (bind_count > 0 && bind_count != jointCnt) + { + LL_WARNS("Mesh") << "Model " << model->mLabel << " has invalid joint bind matrix list." << LL_ENDL; + } + //grab raw position array domVertices* verts = mesh->getVertices(); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 5df3139d0d..666406d039 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -433,46 +433,82 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadBtn->setEnabled(false); } -void populate_list_with_map(LLScrollListCtrl *list, const std::map<std::string, LLVector3> &vector_map) +// Modified cell_params, make sure to clear values if you have to reuse cell_params outside of this function +void add_row_to_list(LLScrollListCtrl *listp, + LLScrollListCell::Params &cell_params, + const LLSD &item_value, + const std::string &name, + const LLSD &vx, + const LLSD &vy, + const LLSD &vz) { - if (vector_map.empty()) + LLScrollListItem::Params item_params; + item_params.value = item_value; + + cell_params.column = "model_name"; + cell_params.value = name; + + item_params.columns.add(cell_params); + + cell_params.column = "axis_x"; + cell_params.value = vx; + item_params.columns.add(cell_params); + + cell_params.column = "axis_y"; + cell_params.value = vy; + item_params.columns.add(cell_params); + + cell_params.column = "axis_z"; + cell_params.value = vz; + + item_params.columns.add(cell_params); + + listp->addRow(item_params); +} + +void populate_list_with_overrides(LLScrollListCtrl *listp, const LLJointOverrideData &data, bool include_overrides) +{ + if (data.mModelsNoOverrides.empty() && data.mPosOverrides.empty()) { return; } + + static const LLSD no_override_placeholder("-"); // LLSD to not conflict in '?' + 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) + std::map<std::string, LLVector3>::const_iterator map_iter = data.mPosOverrides.begin(); + std::map<std::string, LLVector3>::const_iterator map_end = data.mPosOverrides.end(); + while (map_iter != map_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); + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + map_iter->first, + include_overrides ? map_iter->second.mV[VX] : no_override_placeholder, + include_overrides ? map_iter->second.mV[VY] : no_override_placeholder, + include_overrides ? map_iter->second.mV[VZ] : no_override_placeholder); + count++; + map_iter++; + } - list->addRow(item_params); + std::set<std::string>::const_iterator set_iter = data.mModelsNoOverrides.begin(); + std::set<std::string>::const_iterator set_end = data.mModelsNoOverrides.end(); + while (set_iter != set_end) + { + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + *set_iter, + no_override_placeholder, + no_override_placeholder, + no_override_placeholder); count++; - iter++; + set_iter++; } } @@ -493,7 +529,8 @@ void LLFloaterModelPreview::onJointListSelection() { std::string label = selected->getValue().asString(); LLJointOverrideData &data = mJointOverrides[display_lod][label]; - populate_list_with_map(joints_pos, data.mPosOverrides); + bool upload_joint_positions = childGetValue("upload_joints").asBoolean(); + populate_list_with_overrides(joints_pos, data, upload_joint_positions); joint_pos_descr->setTextArg("[JOINT]", label); mSelectedJointName = label; @@ -1285,7 +1322,7 @@ void LLFloaterModelPreview::clearAvatarTab() joint_pos_descr->setTextArg("[JOINT]", std::string("mPelvis")); // Might be better to hide it } -void LLFloaterModelPreview::updateAvatarTab() +void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) { S32 display_lod = mModelPreview->mPreviewLOD; if (mModelPreview->mModel[display_lod].empty()) @@ -1307,10 +1344,22 @@ void LLFloaterModelPreview::updateAvatarTab() LLModelInstance& instance = *model_iter; LLModel* model = instance.mModel; const LLMeshSkinInfo *skin = &model->mSkinInfo; - if (skin->mAlternateBindMatrix.size() > 0) + U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); + U32 bind_count = highlight_overrides ? skin->mAlternateBindMatrix.size() : 0; // simply do not include overrides if data is not needed + if (bind_count > 0 && bind_count != joint_count) + { + std::ostringstream out; + out << "Invalid joint overrides for model " << model->getName(); + out << ". Amount of joints " << joint_count; + out << ", is different from amount of overrides " << bind_count; + LL_INFOS() << out.str() << LL_ENDL; + addStringToLog(out.str(), true); + // Disable overrides for this model + bind_count = 0; + } + if (bind_count > 0) { - U32 count = LLSkinningUtil::getMeshJointCount(skin); - for (U32 j = 0; j < count; ++j) + for (U32 j = 0; j < joint_count; ++j) { const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation(); LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; @@ -1323,7 +1372,14 @@ void LLFloaterModelPreview::updateAvatarTab() data.mHasConflicts = true; } data.mPosOverrides[model->getName()] = jointPos; - + } + } + else + { + for (U32 j = 0; j < joint_count; ++j) + { + LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; + data.mModelsNoOverrides.insert(model->getName()); } } } @@ -1364,6 +1420,10 @@ void LLFloaterModelPreview::updateAvatarTab() cell_params.color = LLColor4::orange; conflicts++; } + if (highlight_overrides && joint_iter->second.mPosOverrides.size() > 0) + { + cell_params.font.style = "BOLD"; + } item_params.columns.add(cell_params); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index ca52312756..48b90e9d44 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -43,7 +43,8 @@ class LLJointOverrideData { public: LLJointOverrideData() : mHasConflicts(false) {}; - std::map<std::string, LLVector3> mPosOverrides; + std::map<std::string, LLVector3> mPosOverrides; // models with overrides + std::set<std::string> mModelsNoOverrides; // models without defined overrides bool mHasConflicts; }; typedef std::map<std::string, LLJointOverrideData> joint_override_data_map_t; @@ -86,7 +87,7 @@ public: 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 updateAvatarTab(bool highlight_overrides); // populates table and data as nessesary void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); void setPreviewLOD(S32 lod); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 9e39d0cf51..21c6895a6c 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2734,6 +2734,10 @@ BOOL LLModelPreview::render() if (upload_joints != mLastJointUpdate) { mLastJointUpdate = upload_joints; + if (fmp) + { + fmp->clearAvatarTab(); + } } for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) @@ -2801,22 +2805,27 @@ BOOL LLModelPreview::render() upload_joints = false; } - if (upload_skin && upload_joints) + if (fmp) { - mFMP->childEnable("lock_scale_if_joint_position"); - if (fmp) + if (upload_skin) { - fmp->updateAvatarTab(); + // will populate list of joints + fmp->updateAvatarTab(upload_joints); } + else + { + fmp->clearAvatarTab(); + } + } + + if (upload_skin && upload_joints) + { + mFMP->childEnable("lock_scale_if_joint_position"); } 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 @@ -3218,9 +3227,12 @@ BOOL LLModelPreview::render() { const LLMeshSkinInfo *skin = &model->mSkinInfo; LLSkinningUtil::initJointNums(&model->mSkinInfo, getPreviewAvatar());// inits skin->mJointNums if nessesary - U32 count = LLSkinningUtil::getMeshJointCount(skin); + U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); + U32 bind_count = skin->mAlternateBindMatrix.size(); - if (joint_overrides && skin->mAlternateBindMatrix.size() > 0) + if (joint_overrides + && bind_count > 0 + && joint_count == bind_count) { // mesh_id is used to determine which mesh gets to // set the joint offset, in the event of a conflict. Since @@ -3231,7 +3243,7 @@ BOOL LLModelPreview::render() // incorrect. LLUUID fake_mesh_id; fake_mesh_id.generate(); - for (U32 j = 0; j < count; ++j) + for (U32 j = 0; j < joint_count; ++j) { LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]); if (joint) @@ -3278,7 +3290,7 @@ BOOL LLModelPreview::render() //build matrix palette LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, + LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, joint_count, skin, getPreviewAvatar()); LLMatrix4a bind_shape_matrix; -- cgit v1.2.3 From c0ed9d28f19bcdde171842370e87eb82cf43b896 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 24 Apr 2020 02:37:35 +0300 Subject: SL-13080 Filter out default overrides --- indra/newview/llfloatermodelpreview.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 666406d039..083c2dab37 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1361,17 +1361,32 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) { for (U32 j = 0; j < joint_count; ++j) { - const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation(); + const LLVector3& joint_pos = 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)) + + LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j], mModelPreview); + if (pJoint) { - // 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; + // see how voavatar uses aboveJointPosThreshold + if (pJoint->aboveJointPosThreshold(joint_pos)) + { + // valid override + if (data.mPosOverrides.size() > 0 + && (data.mPosOverrides.begin()->second - joint_pos).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()] = joint_pos; + } + else + { + // default value, it won't be accounted for by avatar + data.mModelsNoOverrides.insert(model->getName()); + } } - data.mPosOverrides[model->getName()] = jointPos; } } else -- cgit v1.2.3 From 0bc76461fa4445491cf119e80cb854f1d6dd6896 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 24 Apr 2020 02:47:18 +0300 Subject: SL-13080 Mac build fix --- indra/newview/llfloatermodelpreview.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 083c2dab37..ba67f297a0 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -473,7 +473,7 @@ void populate_list_with_overrides(LLScrollListCtrl *listp, const LLJointOverride return; } - static const LLSD no_override_placeholder("-"); // LLSD to not conflict in '?' + static const std::string no_override_placeholder = "-"; S32 count = 0; LLScrollListCell::Params cell_params; @@ -485,13 +485,26 @@ void populate_list_with_overrides(LLScrollListCtrl *listp, const LLJointOverride std::map<std::string, LLVector3>::const_iterator map_end = data.mPosOverrides.end(); while (map_iter != map_end) { - add_row_to_list(listp, - cell_params, - LLSD::Integer(count), - map_iter->first, - include_overrides ? map_iter->second.mV[VX] : no_override_placeholder, - include_overrides ? map_iter->second.mV[VY] : no_override_placeholder, - include_overrides ? map_iter->second.mV[VZ] : no_override_placeholder); + if (include_overrides) + { + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + map_iter->first, + LLSD::Real(map_iter->second.mV[VX]), + LLSD::Real(map_iter->second.mV[VY]), + LLSD::Real(map_iter->second.mV[VZ])); + } + else + { + add_row_to_list(listp, + cell_params, + LLSD::Integer(count), + map_iter->first, + no_override_placeholder, + no_override_placeholder, + no_override_placeholder); + } count++; map_iter++; } -- cgit v1.2.3 From a0e91e9e505e747f876712fe8ec5c250b56e1dcf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 24 Apr 2020 18:05:14 +0300 Subject: SL-307 Improvements to flashing color --- indra/llui/llbutton.cpp | 22 +++++++++++---------- indra/llui/lltabcontainer.cpp | 18 ++++++++--------- indra/llui/lltabcontainer.h | 3 ++- indra/newview/llfloatermodelpreview.cpp | 5 +---- .../textures/containers/TabTop_Right_Flashing.png | Bin 0 -> 252 bytes indra/newview/skins/default/textures/textures.xml | 1 + .../skins/default/xui/en/floater_model_preview.xml | 5 ++++- 7 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 804204cce0..9682c3bc10 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -643,7 +643,8 @@ void LLButton::draw() LLColor4 highlighting_color = LLColor4::white; LLColor4 glow_color = LLColor4::white; LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; - LLUIImage* imagep = NULL; + LLUIImage* imagep = NULL; + LLUIImage* image_glow = NULL; // Cancel sticking of color, if the button is pressed, // or when a flashing of the previously selected button is ended @@ -710,17 +711,18 @@ void LLButton::draw() imagep = mImageDisabled; } + image_glow = imagep; + if (mFlashing) { - // if button should flash and we have icon for flashing, use it as image for button - if(flash && mImageFlash) + if (flash && mImageFlash) { - // setting flash to false to avoid its further influence on glow - flash = false; - imagep = mImageFlash; + // if button should flash and we have icon for flashing, use it as image for button + image_glow = mImageFlash; } - // else use usual flashing via flash_color - else if (mFlashingTimer) + + // provide fade-in and fade-out via flash_color + if (mFlashingTimer) { LLColor4 flash_color = mFlashBgColor.get(); use_glow_effect = TRUE; @@ -811,7 +813,7 @@ void LLButton::draw() if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); + image_glow->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % (mCurGlowStrength * alpha)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -822,7 +824,7 @@ void LLButton::draw() if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - imagep->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); + image_glow->drawSolid(0, y, glow_color % (mCurGlowStrength * alpha)); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 750a3aff9c..e6b43da8e5 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -221,6 +221,7 @@ LLTabContainer::Params::Params() 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), + tabs_flashing_color("tabs_flashing_color"), tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0), use_ellipses("use_ellipses"), font_halign("halign") @@ -261,6 +262,7 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mOpenTabsOnDragAndDrop(p.open_tabs_on_drag_and_drop), mTabIconCtrlPad(p.tab_icon_ctrl_pad), mEnableTabsFlashing(p.enable_tabs_flashing), + mTabsFlashingColor(p.tabs_flashing_color), mUseTabEllipses(p.use_ellipses) { static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0); @@ -282,6 +284,11 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p) mMinTabWidth = tabcntr_vert_tab_min_width; } + if (p.tabs_flashing_color.isProvided()) + { + mEnableTabsFlashing = true; + } + initButtons( ); } @@ -1107,6 +1114,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) // inits flash timer p.button_flash_enable = mEnableTabsFlashing; + p.flash_color = mTabsFlashingColor; // *TODO : It seems wrong not to use p in both cases considering the way p is initialized if (mCustomIconCtrlUsed) @@ -1642,16 +1650,6 @@ 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 5339bec3dd..8f8cedb1b9 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -114,6 +114,7 @@ public: * Enable tab flashing */ Optional<bool> enable_tabs_flashing; + Optional<LLUIColor> tabs_flashing_color; /** * Paddings for LLIconCtrl in case of LLCustomButtonIconCtrl usage(use_custom_icon_ctrl = true) @@ -203,7 +204,6 @@ 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); @@ -317,6 +317,7 @@ private: bool mCustomIconCtrlUsed; bool mOpenTabsOnDragAndDrop; bool mEnableTabsFlashing; + LLUIColor mTabsFlashingColor; S32 mTabIconCtrlPad; bool mUseTabEllipses; }; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ba67f297a0..1d3fb5bcfc 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1519,10 +1519,7 @@ void LLFloaterModelPreview::addStringToLogTab(const std::string& str, bool 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); + mTabContainer->setTabPanelFlashing(panel, true); } } } diff --git a/indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png b/indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png new file mode 100644 index 0000000000..fd13bb699d Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Right_Flashing.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 624dca48d2..980dcf76bf 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -628,6 +628,7 @@ with the same filename but different name <texture name="TabTop_Right_Off" file_name="containers/TabTop_Right_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" /> <texture name="TabTop_Right_Selected" file_name="containers/TabTop_Right_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" /> + <texture name="TabTop_Right_Flashing" file_name="containers/TabTop_Right_Flashing.png" preload="false" scale.left="8" scale.top="8" scale.right="62" scale.bottom="9" /> <texture name="TabTop_Middle_Off" file_name="containers/TabTop_Middle_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="120" scale.bottom="9" /> <texture name="TabTop_Middle_Selected" file_name="containers/TabTop_Middle_Selected.png" preload="false" scale.left="8" scale.top="8" scale.right="96" scale.bottom="9" /> <texture name="TabTop_Left_Off" file_name="containers/TabTop_Left_Off.png" preload="false" scale.left="8" scale.top="8" scale.right="120" scale.bottom="9" /> 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 e8c64dfef7..66878f227b 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -90,7 +90,10 @@ width="635" name="import_tab" tab_position="top" - enable_tabs_flashing="true"> + enable_tabs_flashing="true" + tabs_flashing_color="MenuItemFlashBgColor"> + <last_tab + tab_top_image_flash="TabTop_Right_Flashing"/> <!-- for log tab --> <!-- LOD PANEL --> <panel help_topic="upload_model_lod" -- cgit v1.2.3 From 3cc83b2e37e0e4695410ee10d622e69ce642b7cb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 24 Apr 2020 18:29:18 +0300 Subject: SL-307 Improvements to logging --- indra/newview/llfloatermodelpreview.cpp | 2 +- indra/newview/llmodelpreview.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1d3fb5bcfc..98ffd30bc7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -413,7 +413,7 @@ void LLFloaterModelPreview::loadModel(S32 lod, const std::string& file_name, boo void LLFloaterModelPreview::onClickCalculateBtn() { clearLogTab(); - + addStringToLog("Calculating model data.", false); mModelPreview->rebuildUploadData(); bool upload_skinweights = childGetValue("upload_skin").asBoolean(); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 21c6895a6c..6de88b318a 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -562,6 +562,7 @@ void LLModelPreview::rebuildUploadData() LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; if (!high_lod_model) { + LLFloaterModelPreview::addStringToLog("Model " + instance.mLabel + " has no High Lod (LOD3).", true); setLoadState(LLModelLoader::ERROR_MATERIALS); mFMP->childDisable("calculate_btn"); } @@ -574,6 +575,7 @@ void LLModelPreview::rebuildUploadData() llassert(instance.mLOD[i]); if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt)) { + LLFloaterModelPreview::addStringToLog("Model " + instance.mLabel + " has mismatching materials between lods." , true); setLoadState(LLModelLoader::ERROR_MATERIALS); mFMP->childDisable("calculate_btn"); } @@ -593,7 +595,7 @@ void LLModelPreview::rebuildUploadData() out << bind_rot; LL_WARNS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); + LLFloaterModelPreview::addStringToLog(out, getLoadState() != LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION); setLoadState(LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION); } } @@ -626,7 +628,7 @@ void LLModelPreview::rebuildUploadData() 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); + LLFloaterModelPreview::addStringToLog(out, true); } setLoadState(LLModelLoader::ERROR_MATERIALS); mFMP->childDisable("calculate_btn"); -- cgit v1.2.3 From aa014a65e76a1312dee82de38dc8d73b64e7a8b5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 24 Apr 2020 20:50:57 +0300 Subject: SL-13123 Bind shape matrix orientation warning is misbehaving --- indra/newview/llfloatermodelpreview.cpp | 21 +++++---------------- indra/newview/llfloatermodelpreview.h | 1 - indra/newview/llmodelpreview.cpp | 4 ++++ 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 98ffd30bc7..f609e8a91a 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -180,7 +180,6 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - childSetCommitCallback("upload_skin", onUploadSkinCommit, this); childSetCommitCallback("upload_joints", onUploadJointsCommit, this); childSetCommitCallback("lock_scale_if_joint_position", onUploadJointsCommit, this); @@ -331,7 +330,11 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) if (mModelPreview) { auto name = ctrl->getName(); - mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; + mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; + mModelPreview->refresh(); + mModelPreview->resetPreviewTarget(); + mModelPreview->clearBuffers(); + mModelPreview->mDirty = true; } toggleCalculateButton(true); } @@ -615,20 +618,6 @@ void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) fp->mModelPreview->refresh(); } -//static -void LLFloaterModelPreview::onUploadSkinCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - fp->mModelPreview->refresh(); - fp->mModelPreview->resetPreviewTarget(); - fp->mModelPreview->clearBuffers(); -} - //static void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 48b90e9d44..6ecc279365 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -140,7 +140,6 @@ protected: static void onImportScaleCommit(LLUICtrl*, void*); static void onPelvisOffsetCommit(LLUICtrl*, void*); static void onUploadJointsCommit(LLUICtrl*,void*); - static void onUploadSkinCommit(LLUICtrl*,void*); static void onPreviewLODCommit(LLUICtrl*,void*); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 6de88b318a..dbb2c162a3 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -599,6 +599,10 @@ void LLModelPreview::rebuildUploadData() setLoadState(LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION); } } + else if (getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) + { + setLoadState(LLModelLoader::DONE); + } } instance.mTransform = mat; mUploadData.push_back(instance); -- cgit v1.2.3 From 4ac08f1ac5b003b95fc9087183d03c0291f6554b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Sat, 25 Apr 2020 14:35:44 +0300 Subject: SL-13123 Cleanup --- indra/newview/llfloatermodelpreview.cpp | 26 +++++++------------------- indra/newview/llfloatermodelpreview.h | 1 - indra/newview/llmodelpreview.cpp | 30 ++++++++++++++++++++++-------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f609e8a91a..a52cf981c7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -166,6 +166,7 @@ BOOL LLFloaterModelPreview::postBuild() getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLODParamCommit, this, lod, true)); } + // Upload/avatar options, they need to refresh errors/notifications 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); @@ -180,9 +181,6 @@ BOOL LLFloaterModelPreview::postBuild() childSetCommitCallback("preview_lod_combo", onPreviewLODCommit, this); - childSetCommitCallback("upload_joints", onUploadJointsCommit, this); - childSetCommitCallback("lock_scale_if_joint_position", onUploadJointsCommit, this); - childSetCommitCallback("import_scale", onImportScaleCommit, this); childSetCommitCallback("pelvis_offset", onPelvisOffsetCommit, this); @@ -330,12 +328,15 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) if (mModelPreview) { auto name = ctrl->getName(); + // update the option and notifications + // (this is a bit convoluted, because of the current structure of mModelPreview) mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; - mModelPreview->refresh(); - mModelPreview->resetPreviewTarget(); + mModelPreview->refresh(); // a 'dirty' flag for render + mModelPreview->resetPreviewTarget(); mModelPreview->clearBuffers(); mModelPreview->mDirty = true; - } + } + // set the button visible, it will be refreshed later toggleCalculateButton(true); } @@ -605,19 +606,6 @@ void LLFloaterModelPreview::onPelvisOffsetCommit( LLUICtrl*, void* userdata ) fp->mModelPreview->refresh(); } -//static -void LLFloaterModelPreview::onUploadJointsCommit(LLUICtrl*,void* userdata) -{ - LLFloaterModelPreview *fp =(LLFloaterModelPreview *)userdata; - - if (!fp->mModelPreview) - { - return; - } - - fp->mModelPreview->refresh(); -} - //static void LLFloaterModelPreview::onPreviewLODCommit(LLUICtrl* ctrl, void* userdata) { diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 6ecc279365..7b344ef2b2 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -139,7 +139,6 @@ protected: static void onImportScaleCommit(LLUICtrl*, void*); static void onPelvisOffsetCommit(LLUICtrl*, void*); - static void onUploadJointsCommit(LLUICtrl*,void*); static void onPreviewLODCommit(LLUICtrl*,void*); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index dbb2c162a3..9530e02c06 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -361,6 +361,7 @@ void LLModelPreview::rebuildUploadData() F32 max_scale = 0.f; BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); + U32 load_state = 0; for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) { //for each transform in scene @@ -563,7 +564,7 @@ void LLModelPreview::rebuildUploadData() if (!high_lod_model) { LLFloaterModelPreview::addStringToLog("Model " + instance.mLabel + " has no High Lod (LOD3).", true); - setLoadState(LLModelLoader::ERROR_MATERIALS); + load_state = LLModelLoader::ERROR_MATERIALS; mFMP->childDisable("calculate_btn"); } else @@ -576,7 +577,7 @@ void LLModelPreview::rebuildUploadData() if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt)) { LLFloaterModelPreview::addStringToLog("Model " + instance.mLabel + " has mismatching materials between lods." , true); - setLoadState(LLModelLoader::ERROR_MATERIALS); + load_state = LLModelLoader::ERROR_MATERIALS; mFMP->childDisable("calculate_btn"); } } @@ -588,6 +589,8 @@ void LLModelPreview::rebuildUploadData() LLQuaternion identity; if (!bind_rot.isEqualEps(identity, 0.01)) { + // Bind shape matrix is not in standard X-forward orientation. + // Might be good idea to only show this once. It can be spammy. std::ostringstream out; out << "non-identity bind shape rot. mat is "; out << high_lod_model->mSkinInfo.mBindShapeMatrix; @@ -596,13 +599,9 @@ void LLModelPreview::rebuildUploadData() LL_WARNS() << out.str() << LL_ENDL; LLFloaterModelPreview::addStringToLog(out, getLoadState() != LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION); - setLoadState(LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION); + load_state = LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION; } } - else if (getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) - { - setLoadState(LLModelLoader::DONE); - } } instance.mTransform = mat; mUploadData.push_back(instance); @@ -634,12 +633,27 @@ void LLModelPreview::rebuildUploadData() LL_INFOS() << out.str() << LL_ENDL; LLFloaterModelPreview::addStringToLog(out, true); } - setLoadState(LLModelLoader::ERROR_MATERIALS); + load_state = LLModelLoader::ERROR_MATERIALS; mFMP->childDisable("calculate_btn"); } } } + // Update state for notifications + if (load_state > 0) + { + // encountered issues + setLoadState(load_state); + } + else if (getLoadState() == LLModelLoader::ERROR_MATERIALS + || getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) + { + // This is only valid for these two error types because they are + // only used inside rebuildUploadData() and updateStatusMessages() + // updateStatusMessages() is called after rebuildUploadData() + setLoadState(LLModelLoader::DONE); + } + F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE - 0.1f) / max_scale; F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); -- cgit v1.2.3 From 9fad0d600803bbe438bdfa5a0b3448d193f361c2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 12 May 2020 16:45:59 +0300 Subject: SL-13064 Reverted changes that were causing Artifacts at HD620 --- indra/newview/llmodelpreview.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 9530e02c06..c0de12f58e 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -3133,7 +3133,7 @@ BOOL LLModelPreview::render() } // only do this if mDegenerate was set in the preceding mesh checks [Check this if the ordering ever breaks] - if (pass > 0 && mHasDegenerate) + if (mHasDegenerate) { glLineWidth(PREVIEW_DEG_EDGE_WIDTH); glPointSize(PREVIEW_DEG_POINT_SIZE); @@ -3179,7 +3179,6 @@ BOOL LLModelPreview::render() for (U32 v = 0; v < num_models; ++v) { LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v]; - if (buffer->getNumVerts() < 3)continue; buffer->setBuffer(type_mask & buffer->getTypeMask()); @@ -3190,22 +3189,16 @@ BOOL LLModelPreview::render() LLStrider<U16> idx; buffer->getIndexStrider(idx, 0); - LLVector4a v1, v2, v3; - for (U32 indices_offset = 0; indices_offset < buffer->getNumIndices(); indices_offset += 3) + for (U32 i = 0; i < buffer->getNumIndices(); i += 3) { - v1.setMul(pos[*idx++], scale); - v2.setMul(pos[*idx++], scale); - v3.setMul(pos[*idx++], scale); + LLVector4a v1; v1.setMul(pos[*idx++], scale); + LLVector4a v2; v2.setMul(pos[*idx++], scale); + LLVector4a v3; v3.setMul(pos[*idx++], scale); if (ll_is_degenerate(v1, v2, v3)) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gGL.diffuseColor3fv(PREVIEW_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(PREVIEW_DEG_FILL_COL.mV); - buffer->drawRange(LLRender::TRIANGLES, 0, 2, 3, indices_offset); + buffer->draw(LLRender::LINE_LOOP, 3, i); + buffer->draw(LLRender::POINTS, 3, i); } } } -- cgit v1.2.3 From 70fe69ea43d896da096f767d530f18a702c5d7a6 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Tue, 12 May 2020 19:02:48 +0300 Subject: SL-13189 Mesh uploader - Autofill from _postfixes --- indra/newview/llfloatermodelpreview.cpp | 26 +++++++++ indra/newview/llfloatermodelpreview.h | 4 ++ indra/newview/llmodelpreview.cpp | 95 ++++++++++++++++++++------------- indra/newview/llmodelpreview.h | 3 ++ indra/newview/llviewermenufile.cpp | 2 +- 5 files changed, 93 insertions(+), 37 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index a52cf981c7..f667116ca4 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -395,6 +395,12 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option) setViewOptionEnabled(option, false); } +void LLFloaterModelPreview::loadHighLodModel() +{ + mModelPreview->mLookUpLodFiles = true; + loadModel(3); +} + void LLFloaterModelPreview::loadModel(S32 lod) { mModelPreview->mLoading = true; @@ -1593,6 +1599,26 @@ LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LL assignData(mdl) ; } +void LLFloaterModelPreview::setCtrlLoadFromFile(S32 lod) +{ + if (lod == LLModel::LOD_PHYSICS) + { + LLComboBox* lod_combo = findChild<LLComboBox>("physics_lod_combo"); + if (lod_combo) + { + lod_combo->setCurrentByIndex(5); + } + } + else + { + LLComboBox* lod_combo = findChild<LLComboBox>("lod_source_" + lod_name[lod]); + if (lod_combo) + { + lod_combo->setCurrentByIndex(0); + } + } +} + void LLFloaterModelPreview::setStatusMessage(const std::string& msg) { LLMutexLock lock(mStatusLock); diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 7b344ef2b2..bee64fb501 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -102,6 +102,8 @@ public: void loadModel(S32 lod); void loadModel(S32 lod, const std::string& file_name, bool force_disable_slm = false); + + void loadHighLodModel(); void onViewOptionChecked(LLUICtrl* ctrl); void onUploadOptionChecked(LLUICtrl* ctrl); @@ -174,6 +176,8 @@ protected: void setStatusMessage(const std::string& msg); void addStringToLogTab(const std::string& str, bool flash); + void setCtrlLoadFromFile(S32 lod); + LLModelPreview* mModelPreview; LLPhysicsDecomp::decomp_params mDecompParams; diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index c0de12f58e..04a818b2a4 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -127,6 +127,20 @@ std::string stripSuffix(std::string name) return name; } +std::string getLodSuffix(S32 lod) +{ + std::string suffix; + switch (lod) + { + case LLModel::LOD_IMPOSTOR: suffix = "_LOD0"; break; + case LLModel::LOD_LOW: suffix = "_LOD1"; break; + case LLModel::LOD_MEDIUM: suffix = "_LOD2"; break; + case LLModel::LOD_PHYSICS: suffix = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + return suffix; +} + void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) { LLModelLoader::scene::iterator base_iter = scene.begin(); @@ -181,6 +195,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mDirty = false; mGenLOD = false; mLoading = false; + mLookUpLodFiles = false; mLoadState = LLModelLoader::STARTING; mGroup = 0; mLODFrozen = false; @@ -421,15 +436,7 @@ void LLModelPreview::rebuildUploadData() extensionLOD = mPhysicsSearchLOD; } - std::string toAdd; - switch (extensionLOD) - { - case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; - case LLModel::LOD_LOW: toAdd = "_LOD1"; break; - case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; - case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } + std::string toAdd = getLodSuffix(extensionLOD); if (name_to_match.find(toAdd) == -1) { @@ -456,15 +463,7 @@ void LLModelPreview::rebuildUploadData() std::string name_to_match = instance.mLabel; llassert(!name_to_match.empty()); - std::string toAdd; - switch (searchLOD) - { - case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; - case LLModel::LOD_LOW: toAdd = "_LOD1"; break; - case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; - case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } + std::string toAdd = getLodSuffix(searchLOD); if (name_to_match.find(toAdd) == -1) { @@ -1168,14 +1167,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) if (loaded_name != name) { - switch (loaded_lod) - { - case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; - case LLModel::LOD_LOW: name += "_LOD1"; break; - case LLModel::LOD_MEDIUM: name += "_LOD2"; break; - case LLModel::LOD_PHYSICS: name += "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } + name += getLodSuffix(loaded_lod); if (mImporterDebug) { @@ -1578,16 +1570,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); - std::string name = base->mLabel; - - switch (lod) - { - case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; - case LLModel::LOD_LOW: name += "_LOD1"; break; - case LLModel::LOD_MEDIUM: name += "_LOD2"; break; - case LLModel::LOD_PHYSICS: name += "_PHYS"; break; - case LLModel::LOD_HIGH: break; - } + std::string name = base->mLabel + getLodSuffix(lod); mModel[lod][mdl_idx]->mLabel = name; mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; @@ -2607,10 +2590,45 @@ void LLModelPreview::loadedCallback( } pPreview->mModelLoader->clearLog(); pPreview->loadModelCallback(lod); // removes mModelLoader in some cases + if (pPreview->mLookUpLodFiles && (lod != LLModel::LOD_HIGH)) + { + pPreview->lookupLODModelFiles(lod); + } } } +void LLModelPreview::lookupLODModelFiles(S32 lod) +{ + if (lod == LLModel::LOD_PHYSICS) + { + mLookUpLodFiles = false; + return; + } + S32 next_lod = (lod - 1 >= LLModel::LOD_IMPOSTOR) ? lod - 1 : LLModel::LOD_PHYSICS; + + std::string lod_filename = mLODFile[LLModel::LOD_HIGH]; + std::string ext = ".dae"; + std::string::size_type i = lod_filename.rfind(ext); + if (i != std::string::npos) + { + lod_filename.replace(i, lod_filename.size() - ext.size(), getLodSuffix(next_lod) + ext); + } + if (gDirUtilp->fileExists(lod_filename)) + { + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + fmp->setCtrlLoadFromFile(next_lod); + } + loadModel(lod_filename, next_lod); + } + else + { + lookupLODModelFiles(next_lod); + } +} + void LLModelPreview::stateChangedCallback(U32 state, void* opaque) { LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); @@ -3509,6 +3527,11 @@ bool LLModelPreview::lodQueryCallback() preview->mLodsQuery.pop_back(); preview->genLODs(lod); + if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) + { + preview->lookupLODModelFiles(LLModel::LOD_HIGH); + } + // return false to continue cycle return false; } diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 4c03849d6b..9b8200ab8a 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -206,6 +206,8 @@ protected: static LLJoint* lookupJointByName(const std::string&, void* opaque); static U32 loadTextures(LLImportMaterial& material, void* opaque); + void lookupLODModelFiles(S32 lod); + private: //Utility function for controller vertex compare bool verifyCount(int expected, int result); @@ -243,6 +245,7 @@ protected: U32 mLoadState; bool mResetJoints; bool mModelNoErrors; + bool mLookUpLodFiles; std::map<std::string, bool> mViewOption; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d1d3a7fc12..7706828cec 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -552,7 +552,7 @@ class LLFileUploadModel : public view_listener_t LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model"); if (fmp && !fmp->isModelLoading()) { - fmp->loadModel(3); + fmp->loadHighLodModel(); } return TRUE; -- cgit v1.2.3 From 0570d6d3c1b56ebcd0309153ec0cebc7586a6286 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Mon, 27 Jul 2020 22:32:49 +0300 Subject: SL-13483 Rename Avatar tab to "Rigging" --- indra/newview/llfloatermodelpreview.cpp | 8 ++++---- indra/newview/skins/default/xui/en/floater_model_preview.xml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index f667116ca4..ff024e1d44 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -261,7 +261,7 @@ BOOL LLFloaterModelPreview::postBuild() mUploadLogText = getChild<LLViewerTextEditor>("log_text"); mTabContainer = getChild<LLTabContainer>("import_tab"); - LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); mAvatarTabIndex = mTabContainer->getIndexForPanel(panel); panel->getChild<LLScrollListCtrl>("joints_list")->setCommitCallback(boost::bind(&LLFloaterModelPreview::onJointListSelection, this)); @@ -538,7 +538,7 @@ void populate_list_with_overrides(LLScrollListCtrl *listp, const LLJointOverride void LLFloaterModelPreview::onJointListSelection() { S32 display_lod = mModelPreview->mPreviewLOD; - LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + LLPanel *panel = mTabContainer->getPanelByName("rigging_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"); @@ -1298,7 +1298,7 @@ void LLFloaterModelPreview::addStringToLog(const std::ostringstream& strm, bool void LLFloaterModelPreview::clearAvatarTab() { - LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); joints_list->deleteAllItems(); LLScrollListCtrl *joints_pos = panel->getChild<LLScrollListCtrl>("pos_overrides_list"); @@ -1397,7 +1397,7 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) } } - LLPanel *panel = mTabContainer->getPanelByName("avatar_panel"); + LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); if (joints_list->isEmpty()) 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 66878f227b..4fa0b9af7d 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1173,8 +1173,8 @@ <panel label="Overrides" layout="topleft" - name="avatar_panel" - title="Avatar"> + name="rigging_panel" + title="Rigging"> <view_border bevel_style="none" follows="top|left" -- cgit v1.2.3 From 7a9a114e168ea68345b54e80b3cfbac7deb4764a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine <mnikolenko@productengine.com> Date: Mon, 3 Aug 2020 19:14:09 +0300 Subject: SL-13698 FIXED crash on model upload --- indra/llprimitive/lldaeloader.cpp | 26 +++++++++++++++++----- indra/llprimitive/lldaeloader.h | 2 +- .../skins/default/xui/en/floater_model_preview.xml | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 431443788c..b9c74b7039 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -343,7 +343,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa return LLModel::NO_ERRORS ; } -LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly) +LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg) { domPRef p = poly->getP(); domListOfUInts& idx = p->getValue(); @@ -403,6 +403,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac LLVolumeFace::VertexMapData::PointMap point_map; U32 cur_idx = 0; + bool log_tc_msg = true; for (U32 i = 0; i < vcount.getCount(); ++i) { //for each polygon U32 first_index = 0; @@ -426,8 +427,21 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (tc_source) { - cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], - tc[idx[cur_idx+tc_offset]*2+1]); + U64 idx_x = idx[cur_idx + tc_offset] * 2 + 0; + U64 idx_y = idx[cur_idx + tc_offset] * 2 + 1; + + if (idx_y < tc.getCount()) + { + cv.mTexCoord.setVec(tc[idx_x], tc[idx_y]); + } + else if (log_tc_msg) + { + log_tc_msg = false; + LL_WARNS() << "Texture coordinates data is not complete." << LL_ENDL; + LLSD args; + args["Message"] = "IncompleteTC"; + log_msg.append(args); + } } if (norm_source) @@ -2362,7 +2376,7 @@ LLColor4 LLDAELoader::getDaeColor(daeElement* element) return value; } -bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh) +bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& log_msg) { LLModel::EModelStatus status = LLModel::NO_ERRORS; domTriangles_Array& tris = mesh->getTriangles_array(); @@ -2384,7 +2398,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh) for (U32 i = 0; i < polys.getCount(); ++i) { domPolylistRef& poly = polys.get(i); - status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); + status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly, log_msg); if(status != LLModel::NO_ERRORS) { @@ -2448,7 +2462,7 @@ bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& mo // Get the whole set of volume faces // - addVolumeFacesFromDomMesh(ret, mesh); + addVolumeFacesFromDomMesh(ret, mesh, mWarningsArray); U32 volume_faces = ret->getNumVolumeFaces(); diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h index 4e990dbe5e..b2db538d32 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -89,7 +89,7 @@ protected: //Verify that a controller matches vertex counts bool verifyController( domController* pController ); - static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh); + static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg = LLSD()); static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh); static LLModel* loadModelFromDomMesh(domMesh* mesh); 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 4fa0b9af7d..9c1a9d2880 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -45,6 +45,7 @@ <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> + <string name="IncompleteTC">Texture coordinates data is not complete.</string> <panel follows="top|left" -- cgit v1.2.3 From 3239f3518b835fcc9d709e0ced312e4e82a05118 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 11 Aug 2020 20:43:31 +0300 Subject: SL-13698 Mac build fix --- indra/llprimitive/lldaeloader.cpp | 3 ++- indra/llprimitive/lldaeloader.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index b9c74b7039..3cb58d894e 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -2535,7 +2535,8 @@ bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh) { pModel->ClearFacesAndMaterials(); - addVolumeFacesFromDomMesh(pModel, mesh); + LLSD placeholder; + addVolumeFacesFromDomMesh(pModel, mesh, placeholder); if (pModel->getNumVolumeFaces() > 0) { diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h index b2db538d32..2b211343e1 100644 --- a/indra/llprimitive/lldaeloader.h +++ b/indra/llprimitive/lldaeloader.h @@ -89,7 +89,7 @@ protected: //Verify that a controller matches vertex counts bool verifyController( domController* pController ); - static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg = LLSD()); + static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg); static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh); static LLModel* loadModelFromDomMesh(domMesh* mesh); -- cgit v1.2.3 From 777e896ee4035c61d312563810c507b2bb5382be Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Tue, 11 Aug 2020 21:27:52 +0300 Subject: DRTVWR-482 Use proper reshape procedure and fix hidden borders --- indra/newview/llfloatermodelpreview.cpp | 39 ++++++++++++++++++--------------- indra/newview/llfloatermodelpreview.h | 1 + 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ff024e1d44..ae9350867f 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -279,6 +279,24 @@ BOOL LLFloaterModelPreview::postBuild() return TRUE; } +//----------------------------------------------------------------------------- +// reshape() +//----------------------------------------------------------------------------- + +void LLFloaterModelPreview::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLFloaterModelUploadBase::reshape(width, height, called_from_parent); + + LLView* preview_panel = getChild<LLView>("preview_panel"); + LLRect rect = preview_panel->getRect(); + + if (rect != mPreviewRect) + { + mModelPreview->refresh(); + mPreviewRect = preview_panel->getRect(); + } +} + //----------------------------------------------------------------------------- // LLFloaterModelPreview() //----------------------------------------------------------------------------- @@ -692,29 +710,14 @@ void LLFloaterModelPreview::draw3dPreview() 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.vertex2i(mPreviewRect.mLeft+1, mPreviewRect.mTop-1); gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); + gGL.vertex2i(mPreviewRect.mLeft+1, mPreviewRect.mBottom+1); gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom); + gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mBottom+1); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(mPreviewRect.mRight-1, mPreviewRect.mTop-1); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index bee64fb501..8a01b0c307 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -70,6 +70,7 @@ public: virtual ~LLFloaterModelPreview(); virtual BOOL postBuild(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void initModelPreview(); -- cgit v1.2.3 From d240d381a26605614d1b2ec37861ef22e92e08c2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 12 Aug 2020 00:59:45 +0300 Subject: SL-13583 Some behavior tweaks #1 --- doc/contributions.txt | 1 + indra/newview/skins/default/xui/en/floater_model_preview.xml | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index bf90770807..850b7469fb 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -261,6 +261,7 @@ Benjamin Bigdipper Beth Walcher Beq Janus SL-10288 + SL-13583 Bezilon Kasei Biancaluce Robbiani CT-225 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 9c1a9d2880..02a21764ce 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1331,7 +1331,7 @@ <view_border bevel_style="none" follows="top|left" - height="306" + height="289" layout="topleft" left="3" name="log_tab_border" @@ -1345,7 +1345,7 @@ font="SansSerif" ignore_tab="false" layout="topleft" - height="306" + height="289" left="4" top="0" right="-1" @@ -1356,6 +1356,14 @@ read_only="true" word_wrap="true"> </text_editor> + <check_box + control_name="ImporterDebug" + follows="top|left" + top_pad="9" + left="6" + width="70" + label="Enable detailed logging" + name="verbose_logging"/> </panel> </tab_container> <panel -- cgit v1.2.3 From 1f2ceb97ec4941a43ef3551a9fb41108cb65e1b2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 12 Aug 2020 22:53:23 +0300 Subject: SL-13583 Some behavior tweaks #2 --- indra/newview/llfloatermodelpreview.cpp | 2 ++ indra/newview/llmodelpreview.cpp | 12 ++++++++++++ indra/newview/llmodelpreview.h | 1 + 3 files changed, 15 insertions(+) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index ae9350867f..1aafd52ee7 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -348,6 +348,8 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) auto name = ctrl->getName(); // update the option and notifications // (this is a bit convoluted, because of the current structure of mModelPreview) + // FIX ME! mViewOption is malfunctioning here! mViewOption doesn't have values like "upload_skin"! + // This needs to translate values like "upload_skin" into "show_skin_weights" mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; mModelPreview->refresh(); // a 'dirty' flag for render mModelPreview->resetPreviewTarget(); diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 04a818b2a4..54350fc63d 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -180,6 +180,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) , mResetJoints(false) , mModelNoErrors(true) , mLastJointUpdate(false) + , mFirstSkinUpdate(true) , mHasDegenerate(false) , mImporterDebug(LLCachedControl<bool>(gSavedSettings, "ImporterDebug", false)) { @@ -2799,11 +2800,22 @@ BOOL LLModelPreview::render() { if (flags == LEGACY_RIG_OK) { + if (mFirstSkinUpdate) + { + // auto enable weight upload if weights are present + // (note: all these UI updates need to be somewhere that is not render) + mViewOption["show_skin_weight"] = true; + skin_weight = true; + fmp->childSetValue("upload_skin", true); + mFirstSkinUpdate = false; + } + 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) { diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 9b8200ab8a..3664a27a72 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -301,6 +301,7 @@ protected: U32 mLegacyRigFlags; bool mLastJointUpdate; + bool mFirstSkinUpdate; JointNameSet mJointsFromNode; JointTransformMap mJointTransformMap; -- cgit v1.2.3 From 0ee7e9dadb0b9d6b6c4007faafe1277cee64392d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 19 Aug 2020 23:26:44 +0300 Subject: SL-13821 Fix upload options affecting preview options incorrectly --- indra/newview/llfloatermodelpreview.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 1aafd52ee7..d03b526dce 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -346,11 +346,37 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) if (mModelPreview) { auto name = ctrl->getName(); + bool value = ctrl->getValue().asBoolean(); // update the option and notifications // (this is a bit convoluted, because of the current structure of mModelPreview) - // FIX ME! mViewOption is malfunctioning here! mViewOption doesn't have values like "upload_skin"! - // This needs to translate values like "upload_skin" into "show_skin_weights" - mModelPreview->mViewOption[name] = !mModelPreview->mViewOption[name]; + if (name == "upload_skin") + { + childSetValue("show_skin_weight", value); + mModelPreview->mViewOption["show_skin_weight"] = value; + if (!value) + { + mModelPreview->mViewOption["show_joint_overrides"] = false; + mModelPreview->mViewOption["show_joint_positions"] = false; + } + } + else if (name == "upload_joints") + { + if (mModelPreview->mViewOption["show_skin_weight"]) + { + childSetValue("show_joint_overrides", value); + mModelPreview->mViewOption["show_joint_overrides"] = value; + } + } + else if (name == "upload_textures") + { + childSetValue("show_textures", value); + mModelPreview->mViewOption["show_textures"] = value; + } + else if (name == "lock_scale_if_joint_position") + { + mModelPreview->mViewOption["lock_scale_if_joint_position"] = value; + } + mModelPreview->refresh(); // a 'dirty' flag for render mModelPreview->resetPreviewTarget(); mModelPreview->clearBuffers(); -- cgit v1.2.3 From bdedfb3755d54a6b4468a5251c9ddeae2b092d37 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Fri, 28 Aug 2020 21:00:04 +0300 Subject: SL-13566 'Use Joint Positions' Option causes collapsed Joints for some files --- indra/llprimitive/lldaeloader.cpp | 104 +++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 3cb58d894e..d2aa3d8dc6 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1229,7 +1229,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do for (S32 i = 0; i < childCount; ++i) { domNode* pNode = daeSafeCast<domNode>(children[i]); - if ( isNodeAJoint( pNode ) ) + if (pNode) { processJointNode( pNode, mJointList ); } @@ -1854,59 +1854,61 @@ void LLDAELoader::processJointNode( domNode* pNode, JointTransformMap& jointTran //LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL; //1. handle the incoming node - extract out translation via SID or element + if (isNodeAJoint(pNode)) + { + LLMatrix4 workingTransform; - LLMatrix4 workingTransform; - - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA( pNode, "./translate" ); - domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); - daeSIDResolver jointResolverB( pNode, "./location" ); - domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolverA(pNode, "./translate"); + domTranslate* pTranslateA = daeSafeCast<domTranslate>(jointResolverA.getElement()); + daeSIDResolver jointResolverB(pNode, "./location"); + domTranslate* pTranslateB = daeSafeCast<domTranslate>(jointResolverB.getElement()); - //Translation via SID was successful - if ( pTranslateA ) - { - extractTranslation( pTranslateA, workingTransform ); - } - else - if ( pTranslateB ) - { - extractTranslation( pTranslateB, workingTransform ); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); - if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) - { - //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; - daeSIDResolver jointResolver( pNode, "./matrix" ); - domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() ); - if ( pMatrix ) - { - //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; - domFloat4x4 domArray = pMatrix->getValue(); - for ( int i = 0; i < 4; i++ ) - { - for( int j = 0; j < 4; j++ ) - { - workingTransform.mMatrix[i][j] = domArray[i + j*4]; - } - } - } - else - { - LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL; - } - } - else - { - extractTranslationViaElement( pTranslateElement, workingTransform ); - } - } + //Translation via SID was successful + if (pTranslateA) + { + extractTranslation(pTranslateA, workingTransform); + } + else + if (pTranslateB) + { + extractTranslation(pTranslateB, workingTransform); + } + else + { + //Translation via child from element + daeElement* pTranslateElement = getChildFromElement(pNode, "translate"); + if (!pTranslateElement || pTranslateElement->typeID() != domTranslate::ID()) + { + //LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; + daeSIDResolver jointResolver(pNode, "./matrix"); + domMatrix* pMatrix = daeSafeCast<domMatrix>(jointResolver.getElement()); + if (pMatrix) + { + //LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; + domFloat4x4 domArray = pMatrix->getValue(); + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 4; j++) + { + workingTransform.mMatrix[i][j] = domArray[i + j * 4]; + } + } + } + else + { + LL_WARNS() << "The found element is not translate or matrix node - most likely a corrupt export!" << LL_ENDL; + } + } + else + { + extractTranslationViaElement(pTranslateElement, workingTransform); + } + } - //Store the working transform relative to the nodes name. - jointTransforms[ pNode->getName() ] = workingTransform; + //Store the working transform relative to the nodes name. + jointTransforms[pNode->getName()] = workingTransform; + } //2. handle the nodes children -- cgit v1.2.3 From 1ef45913812cc65a5b18a1c0c9248fecd48f06c1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Wed, 23 Sep 2020 12:10:06 +0300 Subject: SL-13821 Fixed checkbox not disabling --- indra/newview/llfloatermodelpreview.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d03b526dce..b9c03f66a3 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -357,6 +357,8 @@ void LLFloaterModelPreview::onUploadOptionChecked(LLUICtrl* ctrl) { mModelPreview->mViewOption["show_joint_overrides"] = false; mModelPreview->mViewOption["show_joint_positions"] = false; + childSetValue("show_joint_overrides", false); + childSetValue("show_joint_positions", false); } } else if (name == "upload_joints") -- cgit v1.2.3 From 89839721eadf0b5379042530e01c9e5061ba6c35 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <andreykproductengine@lindenlab.com> Date: Thu, 24 Sep 2020 23:52:53 +0300 Subject: SL-13888 Restore back face culling being accidently removed in SL-12781 Due to conflicts picked up ptolemy's fix manually --- indra/newview/llmodelpreview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 54350fc63d..d60d1d748e 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2732,6 +2732,7 @@ BOOL LLModelPreview::render() LLGLSUIDefault def; // GL_BLEND, GL_ALPHA_TEST, GL_CULL_FACE, depth test LLGLDisable no_blend(GL_BLEND); + LLGLEnable cull(GL_CULL_FACE); LLGLDepthTest depth(GL_FALSE); // SL-12781 disable z-buffer to render background color LLGLDisable fog(GL_FOG); -- cgit v1.2.3 From a2c8c8238cfb109e0da81363995e08e99173426f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed <nat@lindenlab.com> Date: Wed, 14 Oct 2020 14:55:31 -0400 Subject: Increment viewer version to 6.4.11 following promotion of DRTVWR-482 --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index b03e20c456..e5a66bad38 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.4.10 +6.4.11 -- cgit v1.2.3