summaryrefslogtreecommitdiff
path: root/indra/newview/llpanelface.cpp
diff options
context:
space:
mode:
authorRye <rye@alchemyviewer.org>2025-08-20 18:04:55 -0400
committerRye <rye@alchemyviewer.org>2025-08-20 18:04:55 -0400
commitba30737d8f4add8ddd8c77d18df6497b46583fe9 (patch)
tree81e5412a364ff80b5250fe6db9e653d35621c20e /indra/newview/llpanelface.cpp
parentf0db568bf8d313a00e10c1c4ee4dd7f716a9d987 (diff)
parentd5f748c91c650a2ec534c497b9e098ccb317d70b (diff)
Merge branch 'develop' of github.com:secondlife/viewer into rye/infinitemac
Diffstat (limited to 'indra/newview/llpanelface.cpp')
-rw-r--r--indra/newview/llpanelface.cpp884
1 files changed, 617 insertions, 267 deletions
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index b7d9df6ea6..3ab48f69c8 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -162,6 +162,36 @@ void LLPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
}
+void LLPanelFace::updateSelectedGLTFMaterialsWithScale(std::function<void(LLGLTFMaterial*, const F32, const F32)> func)
+{
+ struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor
+ {
+ LLSelectedTEGLTFMaterialFunctor(std::function<void(LLGLTFMaterial*, const F32, const F32)> func) : mFunc(func) {}
+ virtual ~LLSelectedTEGLTFMaterialFunctor() {};
+ bool apply(LLViewerObject* object, S32 face) override
+ {
+ LLGLTFMaterial new_override;
+ const LLTextureEntry* tep = object->getTE(face);
+ if (tep->getGLTFMaterialOverride())
+ {
+ new_override = *tep->getGLTFMaterialOverride();
+ }
+
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+ mFunc(&new_override, object->getScale().mV[s_axis], object->getScale().mV[t_axis]);
+ LLGLTFMaterialList::queueModify(object, face, &new_override);
+
+ return true;
+ }
+
+ std::function<void(LLGLTFMaterial*, const F32, const F32)> mFunc;
+ } select_func(func);
+
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
+}
+
template<typename T>
void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& value, bool& identical, bool has_tolerance, T tolerance)
{
@@ -182,6 +212,36 @@ void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& v
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance);
}
+void getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo channel, F32& repeats, bool& identical)
+{
+ // The All channel should read base color values
+ if (channel == LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT)
+ channel = LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR;
+
+ struct LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor : public LLSelectedTEGetFunctor<F32>
+ {
+ LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor(LLGLTFMaterial::TextureInfo channel) : mChannel(channel) {}
+ virtual ~LLSelectedTEGetGLTFMaterialMaxRepeatsFunctor() {};
+ F32 get(LLViewerObject* object, S32 face) override
+ {
+ const LLTextureEntry* tep = object->getTE(face);
+ const LLGLTFMaterial* render_material = tep->getGLTFRenderMaterial();
+ if (!render_material)
+ return 0.f;
+
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+ F32 repeats_u = render_material->mTextureTransform[mChannel].mScale[VX] / object->getScale().mV[s_axis];
+ F32 repeats_v = render_material->mTextureTransform[mChannel].mScale[VY] / object->getScale().mV[t_axis];
+ return llmax(repeats_u, repeats_v);
+ }
+
+ LLGLTFMaterial::TextureInfo mChannel;
+ } max_repeats_func(channel);
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&max_repeats_func, repeats);
+}
+
BOOST_STATIC_ASSERT(MATTYPE_DIFFUSE == LLRender::DIFFUSE_MAP && MATTYPE_NORMAL == LLRender::NORMAL_MAP && MATTYPE_SPECULAR == LLRender::SPECULAR_MAP);
//
@@ -216,7 +276,7 @@ LLRender::eTexIndex LLPanelFace::getMatTextureChannel()
return LLRender::NORMAL_MAP;
break;
case MATTYPE_SPECULAR: // "Shininess (specular)"
- if (getCurrentNormalMap().notNull())
+ if (getCurrentSpecularMap().notNull())
return LLRender::SPECULAR_MAP;
break;
}
@@ -322,6 +382,7 @@ bool LLPanelFace::postBuild()
getChildSetCommitCallback(mPBRScaleU, "gltfTextureScaleU", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureScaleU(); });
getChildSetCommitCallback(mPBRScaleV, "gltfTextureScaleV", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureScaleV(); });
+ getChildSetCommitCallback(mPBRRepeat, "gltfRptctrl", [&](LLUICtrl*, const LLSD&) { onCommitGLTFRepeatsPerMeter(); });
getChildSetCommitCallback(mPBRRotate, "gltfTextureRotation", [&](LLUICtrl*, const LLSD&) { onCommitGLTFRotation(); });
getChildSetCommitCallback(mPBROffsetU, "gltfTextureOffsetU", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureOffsetU(); });
getChildSetCommitCallback(mPBROffsetV, "gltfTextureOffsetV", [&](LLUICtrl*, const LLSD&) { onCommitGLTFTextureOffsetV(); });
@@ -482,10 +543,6 @@ LLPanelFace::~LLPanelFace()
void LLPanelFace::onVisibilityChange(bool new_visibility)
{
- if (new_visibility)
- {
- gAgent.showLatestFeatureNotification("gltf");
- }
LLPanel::onVisibilityChange(new_visibility);
}
@@ -1106,6 +1163,63 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
updateVisibility(objectp);
+ bool missing_asset = false;
+ {
+ LLGLenum image_format = GL_RGB;
+ bool identical_image_format = false;
+ LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset);
+
+ if (!missing_asset)
+ {
+ mIsAlpha = false;
+ switch (image_format)
+ {
+ case GL_RGBA:
+ case GL_ALPHA:
+ {
+ mIsAlpha = true;
+ }
+ break;
+
+ case GL_RGB:
+ break;
+ default:
+ {
+ LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Don't know image's properties, use material's mode value
+ mIsAlpha = true;
+ }
+
+ // Diffuse Alpha Mode
+ // Init to the default that is appropriate for the alpha content of the asset
+ //
+ U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+ bool identical_alpha_mode = false;
+
+ // See if that's been overridden by a material setting for same...
+ //
+ LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha);
+
+ // it is invalid to have any alpha mode other than blend if transparency is greater than zero ...
+ // Want masking? Want emissive? Tough! You get BLEND!
+ alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode;
+
+ // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none
+ alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+ mComboAlphaMode->getSelectionInterface()->selectNthItem(alpha_mode);
+ updateAlphaControls();
+
+ mExcludeWater &= (LLMaterial::DIFFUSE_ALPHA_MODE_BLEND == alpha_mode);
+ }
+
// Water exclusion
{
mCheckHideWater->setEnabled(editable && !has_pbr_material && !isMediaTexSelected());
@@ -1188,65 +1302,11 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
// Texture
{
- LLGLenum image_format = GL_RGB;
- bool identical_image_format = false;
- bool missing_asset = false;
- LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset);
-
- if (!missing_asset)
- {
- mIsAlpha = false;
- switch (image_format)
- {
- case GL_RGBA:
- case GL_ALPHA:
- {
- mIsAlpha = true;
- }
- break;
-
- case GL_RGB: break;
- default:
- {
- LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
- }
- break;
- }
- }
- else
- {
- // Don't know image's properties, use material's mode value
- mIsAlpha = true;
- }
-
if (LLViewerMedia::getInstance()->textureHasMedia(id))
{
mBtnAlign->setEnabled(editable);
}
- // Diffuse Alpha Mode
-
- // Init to the default that is appropriate for the alpha content of the asset
- //
- U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-
- bool identical_alpha_mode = false;
-
- // See if that's been overridden by a material setting for same...
- //
- LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha);
-
- // it is invalid to have any alpha mode other than blend if transparency is greater than zero ...
- // Want masking? Want emissive? Tough! You get BLEND!
- alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode;
-
- // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none
- alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
-
- mComboAlphaMode->getSelectionInterface()->selectNthItem(alpha_mode);
-
- updateAlphaControls();
-
if (mTextureCtrl)
{
if (identical_diffuse)
@@ -1395,9 +1455,18 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
spec_scale_s = editable ? spec_scale_s : 1.0f;
spec_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
- mTexScaleU->setValue(diff_scale_s);
- mShinyScaleU->setValue(spec_scale_s);
- mBumpyScaleU->setValue(norm_scale_s);
+ if (force_set_values)
+ {
+ mTexScaleU->forceSetValue(diff_scale_s);
+ mShinyScaleU->forceSetValue(spec_scale_s);
+ mBumpyScaleU->forceSetValue(norm_scale_s);
+ }
+ else
+ {
+ mTexScaleU->setValue(diff_scale_s);
+ mShinyScaleU->setValue(spec_scale_s);
+ mBumpyScaleU->setValue(norm_scale_s);
+ }
mTexScaleU->setEnabled(editable && has_material);
mShinyScaleU->setEnabled(editable && has_material && specmap_id.notNull());
@@ -1445,13 +1514,16 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
if (force_set_values)
{
mTexScaleV->forceSetValue(diff_scale_t);
+ mShinyScaleV->forceSetValue(spec_scale_t);
+ mBumpyScaleV->forceSetValue(norm_scale_t);
}
else
{
mTexScaleV->setValue(diff_scale_t);
+ mShinyScaleV->setValue(spec_scale_t);
+ mBumpyScaleV->setValue(norm_scale_t);
}
- mShinyScaleV->setValue(spec_scale_t);
- mBumpyScaleV->setValue(norm_scale_t);
+
mTexScaleV->setTentative(LLSD(diff_scale_tentative));
mShinyScaleV->setTentative(LLSD(spec_scale_tentative));
@@ -1591,36 +1663,57 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
F32 repeats_norm = 1.f;
F32 repeats_spec = 1.f;
+ F32 repeats_pbr_basecolor = 1.f;
+ F32 repeats_pbr_metallic_roughness = 1.f;
+ F32 repeats_pbr_normal = 1.f;
+ F32 repeats_pbr_emissive = 1.f;
+
bool identical_diff_repeats = false;
bool identical_norm_repeats = false;
bool identical_spec_repeats = false;
- LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
- LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
- LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);
+ bool identical_pbr_basecolor_repeats = false;
+ bool identical_pbr_metallic_roughness_repeats = false;
+ bool identical_pbr_normal_repeats = false;
+ bool identical_pbr_emissive_repeats = false;
{
+ LLSpinCtrl* repeats_spin_ctrl = nullptr;
S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0;
bool enabled = editable && (index != 1);
bool identical_repeats = true;
S32 material_selection = mComboMatMedia->getCurrentIndex();
F32 repeats = 1.0f;
- U32 material_type = MATTYPE_DIFFUSE;
- if (material_selection == MATMEDIA_MATERIAL)
+ LLRender::eTexIndex material_channel = LLRender::DIFFUSE_MAP;
+ if (material_selection != MATMEDIA_PBR)
{
- material_type = mRadioMaterialType->getSelectedIndex();
+ repeats_spin_ctrl = mTexRepeat;
+ material_channel = getMatTextureChannel();
+ LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
+ LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
+ LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);
}
else if (material_selection == MATMEDIA_PBR)
{
+ repeats_spin_ctrl = mPBRRepeat;
enabled = editable && has_pbr_material;
- material_type = mRadioPbrType->getSelectedIndex();
+ material_channel = getPBRTextureChannel();
+
+ getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR,
+ repeats_pbr_basecolor, identical_pbr_basecolor_repeats);
+ getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS,
+ repeats_pbr_metallic_roughness, identical_pbr_metallic_roughness_repeats);
+ getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL,
+ repeats_pbr_normal, identical_pbr_normal_repeats);
+ getSelectedGLTFMaterialMaxRepeats(LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_EMISSIVE,
+ repeats_pbr_emissive, identical_pbr_emissive_repeats);
}
- switch (material_type)
+ switch (material_channel)
{
default:
- case MATTYPE_DIFFUSE:
+ case LLRender::DIFFUSE_MAP:
if (material_selection != MATMEDIA_PBR)
{
enabled = editable && !id.isNull();
@@ -1628,7 +1721,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
identical_repeats = identical_diff_repeats;
repeats = repeats_diff;
break;
- case MATTYPE_SPECULAR:
+ case LLRender::SPECULAR_MAP:
if (material_selection != MATMEDIA_PBR)
{
enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull()));
@@ -1636,7 +1729,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
identical_repeats = identical_spec_repeats;
repeats = repeats_spec;
break;
- case MATTYPE_NORMAL:
+ case LLRender::NORMAL_MAP:
if (material_selection != MATMEDIA_PBR)
{
enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()));
@@ -1644,6 +1737,23 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
identical_repeats = identical_norm_repeats;
repeats = repeats_norm;
break;
+ case LLRender::NUM_TEXTURE_CHANNELS:
+ case LLRender::BASECOLOR_MAP:
+ identical_repeats = identical_pbr_basecolor_repeats;
+ repeats = repeats_pbr_basecolor;
+ break;
+ case LLRender::METALLIC_ROUGHNESS_MAP:
+ identical_repeats = identical_pbr_metallic_roughness_repeats;
+ repeats = repeats_pbr_metallic_roughness;
+ break;
+ case LLRender::GLTF_NORMAL_MAP:
+ identical_repeats = identical_pbr_normal_repeats;
+ repeats = repeats_pbr_normal;
+ break;
+ case LLRender::EMISSIVE_MAP:
+ identical_repeats = identical_pbr_emissive_repeats;
+ repeats = repeats_pbr_emissive;
+ break;
}
bool repeats_tentative = !identical_repeats;
@@ -1651,14 +1761,14 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
if (force_set_values)
{
// onCommit, previosly edited element updates related ones
- mTexRepeat->forceSetValue(editable ? repeats : 1.0f);
+ repeats_spin_ctrl->forceSetValue(editable ? repeats : 1.0f);
}
else
{
- mTexRepeat->setValue(editable ? repeats : 1.0f);
+ repeats_spin_ctrl->setValue(editable ? repeats : 1.0f);
}
- mTexRepeat->setTentative(LLSD(repeats_tentative));
- mTexRepeat->setEnabled(has_material && !identical_planar_texgen && enabled);
+ repeats_spin_ctrl->setTentative(LLSD(repeats_tentative));
+ repeats_spin_ctrl->setEnabled(!identical_planar_texgen && enabled);
}
}
@@ -1804,6 +1914,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
}
mLabelColorTransp->setEnabled(false);
mTexRepeat->setEnabled(false);
+ mPBRRepeat->setEnabled(false);
mLabelTexGen->setEnabled(false);
mLabelShininess->setEnabled(false);
mLabelBumpiness->setEnabled(false);
@@ -1999,6 +2110,7 @@ void LLPanelFace::updateVisibilityGLTF(LLViewerObject* objectp /*= nullptr */)
mPBRRotate->setVisible(show_pbr);
mPBROffsetU->setVisible(show_pbr);
mPBROffsetV->setVisible(show_pbr);
+ mPBRRepeat->setVisible(show_pbr);
}
void LLPanelFace::updateCopyTexButton()
@@ -2093,7 +2205,7 @@ void LLPanelFace::refreshMedia()
// check if all faces have media(or, all dont have media)
- LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media);
+ bool identical_has_media_info = selected_objects->getSelectedTEValue(&func, bool_has_media);
const LLMediaEntry default_media_data;
@@ -2115,7 +2227,8 @@ void LLPanelFace::refreshMedia()
} func_media_data(default_media_data);
LLMediaEntry media_data_get;
- LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get));
+ bool multiple_media = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get));
+ bool multiple_valid_media = false;
std::string multi_media_info_str = LLTrans::getString("Multiple Media");
std::string media_title = "";
@@ -2124,12 +2237,12 @@ void LLPanelFace::refreshMedia()
mAddMedia->setEnabled(editable);
// IF all the faces have media (or all dont have media)
- if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo)
+ if (identical_has_media_info)
{
// TODO: get media title and set it.
mTitleMediaText->clear();
// if identical is set, all faces are same (whether all empty or has the same media)
- if (!(LLFloaterMediaSettings::getInstance()->mMultipleMedia))
+ if (!multiple_media)
{
// Media data is valid
if (media_data_get != default_media_data)
@@ -2150,9 +2263,9 @@ void LLPanelFace::refreshMedia()
else // not all face has media but at least one does.
{
// seleted faces have not identical value
- LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
+ multiple_valid_media = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
- if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
+ if (multiple_valid_media)
{
media_title = multi_media_info_str;
}
@@ -2189,7 +2302,7 @@ void LLPanelFace::refreshMedia()
// load values for media settings
updateMediaSettings();
- LLFloaterMediaSettings::initValues(mMediaSettings, editable);
+ LLFloaterMediaSettings::initValues(mMediaSettings, editable, identical_has_media_info, multiple_media, multiple_valid_media);
}
void LLPanelFace::unloadMedia()
@@ -3262,6 +3375,7 @@ void LLPanelFace::onSelectNormalTexture(const LLSD& data)
// TODO: test if there is media on the item and only allow editing if present
void LLPanelFace::onClickBtnEditMedia()
{
+ LLFloaterMediaSettings::getInstance(); // make sure floater we are about to open exists before refreshMedia
refreshMedia();
LLFloaterReg::showInstance("media_settings");
}
@@ -3280,6 +3394,7 @@ void LLPanelFace::onClickBtnAddMedia()
// check if multiple faces are selected
if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())
{
+ LLFloaterMediaSettings::getInstance(); // make sure floater we are about to open exists before refreshMedia
refreshMedia();
LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), multipleFacesSelectedConfirm);
}
@@ -3644,23 +3759,13 @@ void LLPanelFace::onCommitRepeatsPerMeter()
bool identical_scale_t = false;
LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s);
- LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t);
+ LLSelectedTE::getObjectScaleT(obj_scale_t, identical_scale_t);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
-
- mBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
- mBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
-
- LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter);
- LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter);
-
- mShinyScaleU->setValue(obj_scale_s * repeats_per_meter);
- mShinyScaleV->setValue(obj_scale_t * repeats_per_meter);
-
- LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter);
- LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter);
+ LLSelectedTEMaterial::selectionNormalScaleAutofit(this, repeats_per_meter);
+ LLSelectedTEMaterial::selectionSpecularScaleAutofit(this, repeats_per_meter);
}
else
{
@@ -3671,18 +3776,10 @@ void LLPanelFace::onCommitRepeatsPerMeter()
LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
break;
case MATTYPE_NORMAL:
- mBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
- mBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
-
- LLSelectedTEMaterial::setNormalRepeatX(this, obj_scale_s * repeats_per_meter);
- LLSelectedTEMaterial::setNormalRepeatY(this, obj_scale_t * repeats_per_meter);
+ LLSelectedTEMaterial::selectionNormalScaleAutofit(this, repeats_per_meter);
break;
case MATTYPE_SPECULAR:
- mBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
- mBumpyScaleV->setValue(obj_scale_t * repeats_per_meter);
-
- LLSelectedTEMaterial::setSpecularRepeatX(this, obj_scale_s * repeats_per_meter);
- LLSelectedTEMaterial::setSpecularRepeatY(this, obj_scale_t * repeats_per_meter);
+ LLSelectedTEMaterial::selectionSpecularScaleAutofit(this, repeats_per_meter);
break;
default:
llassert(false);
@@ -3693,6 +3790,21 @@ void LLPanelFace::onCommitRepeatsPerMeter()
updateUI(true);
}
+// Commit the number of GLTF repeats per meter
+void LLPanelFace::onCommitGLTFRepeatsPerMeter()
+{
+ F32 repeats_per_meter = (F32)mPBRRepeat->getValue().asReal();
+
+ LLGLTFMaterial::TextureInfo material_type = getPBRTextureInfo();
+ updateGLTFTextureTransformWithScale(material_type, [&](LLGLTFMaterial::TextureTransform* new_transform, F32 scale_s, F32 scale_t)
+ {
+ new_transform->mScale.mV[VX] = scale_s * repeats_per_meter;
+ new_transform->mScale.mV[VY] = scale_t * repeats_per_meter;
+ });
+
+ updateUI(true);
+}
+
struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor
{
virtual bool apply(LLViewerObject* object, S32 te)
@@ -4009,6 +4121,85 @@ void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te)
}
}
+void set_item_availability(
+ const LLUUID& id,
+ LLSD& dest,
+ const std::string& modifier,
+ bool is_creator,
+ std::map<LLUUID, LLUUID> &asset_item_map,
+ LLViewerObject* objectp)
+{
+ if (id.isNull())
+ {
+ return;
+ }
+
+ LLUUID item_id;
+ bool from_library = get_is_predefined_texture(id);
+ bool full_perm = from_library;
+ full_perm |= is_creator;
+
+ if (!full_perm)
+ {
+ std::map<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id);
+ if (iter != asset_item_map.end())
+ {
+ item_id = iter->second;
+ }
+ else
+ {
+ // What this does is simply searches inventory for item with same asset id,
+ // as result it is Hightly unreliable, leaves little control to user, borderline hack
+ // but there are little options to preserve permissions - multiple inventory
+ // items might reference same asset and inventory search is expensive.
+ bool no_transfer = false;
+ if (objectp->getInventoryItemByAsset(id))
+ {
+ no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm();
+ }
+ item_id = get_copy_free_item_by_asset_id(id, no_transfer);
+ // record value to avoid repeating inventory search when possible
+ asset_item_map[id] = item_id;
+ }
+ }
+
+ if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID()))
+ {
+ full_perm = true;
+ from_library = true;
+ }
+
+ dest[modifier + "itemfullperm"] = full_perm;
+ dest[modifier + "fromlibrary"] = from_library;
+
+ // If full permission object, texture is free to copy,
+ // but otherwise we need to check inventory and extract permissions
+ //
+ // Normally we care only about restrictions for current user and objects
+ // don't inherit any 'next owner' permissions from texture, so there is
+ // no need to record item id if full_perm==true
+ if (!full_perm && item_id.notNull())
+ {
+ LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+ if (itemp)
+ {
+ LLPermissions item_permissions = itemp->getPermissions();
+ if (item_permissions.allowOperationBy(PERM_COPY,
+ gAgent.getID(),
+ gAgent.getGroupID()))
+ {
+ dest[modifier + "itemid"] = item_id;
+ dest[modifier + "itemfullperm"] = itemp->getIsFullPerm();
+ if (!itemp->isFinished())
+ {
+ // needed for dropTextureAllFaces
+ LLInventoryModelBackgroundFetch::instance().start(item_id, false);
+ }
+ }
+ }
+ }
+}
+
void LLPanelFace::onCopyTexture()
{
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
@@ -4046,6 +4237,7 @@ void LLPanelFace::onCopyTexture()
if (tep)
{
LLSD te_data;
+ LLUUID pbr_id = objectp->getRenderMaterialID(te);
// asLLSD() includes media
te_data["te"] = tep->asLLSD();
@@ -4054,21 +4246,20 @@ void LLPanelFace::onCopyTexture()
te_data["te"]["bumpshiny"] = tep->getBumpShiny();
te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright();
te_data["te"]["texgen"] = tep->getTexGen();
- te_data["te"]["pbr"] = objectp->getRenderMaterialID(te);
+ te_data["te"]["pbr"] = pbr_id;
if (tep->getGLTFMaterialOverride() != nullptr)
{
te_data["te"]["pbr_override"] = tep->getGLTFMaterialOverride()->asJSON();
}
- if (te_data["te"].has("imageid"))
+ if (te_data["te"].has("imageid") || pbr_id.notNull())
{
- LLUUID item_id;
- LLUUID id = te_data["te"]["imageid"].asUUID();
- bool from_library = get_is_predefined_texture(id);
- bool full_perm = from_library;
+ LLUUID img_id = te_data["te"]["imageid"].asUUID();
+ bool pbr_from_library = false;
+ bool pbr_full_perm = false;
+ bool is_creator = false;
- if (!full_perm
- && objectp->permCopy()
+ if (objectp->permCopy()
&& objectp->permTransfer()
&& objectp->permModify())
{
@@ -4078,66 +4269,31 @@ void LLPanelFace::onCopyTexture()
std::string creator_app_link;
LLUUID creator_id;
LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link);
- full_perm = objectp->mOwnerID == creator_id;
+ is_creator = objectp->mOwnerID == creator_id;
}
- if (id.notNull() && !full_perm)
+ // check permissions for blin-phong/diffuse image and for pbr asset
+ if (img_id.notNull())
{
- std::map<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id);
- if (iter != asset_item_map.end())
- {
- item_id = iter->second;
- }
- else
- {
- // What this does is simply searches inventory for item with same asset id,
- // as result it is Hightly unreliable, leaves little control to user, borderline hack
- // but there are little options to preserve permissions - multiple inventory
- // items might reference same asset and inventory search is expensive.
- bool no_transfer = false;
- if (objectp->getInventoryItemByAsset(id))
- {
- no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm();
- }
- item_id = get_copy_free_item_by_asset_id(id, no_transfer);
- // record value to avoid repeating inventory search when possible
- asset_item_map[id] = item_id;
- }
+ set_item_availability(img_id, te_data["te"], "img", is_creator, asset_item_map, objectp);
}
-
- if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID()))
+ if (pbr_id.notNull())
{
- full_perm = true;
- from_library = true;
- }
+ set_item_availability(pbr_id, te_data["te"], "pbr", is_creator, asset_item_map, objectp);
- {
- te_data["te"]["itemfullperm"] = full_perm;
- te_data["te"]["fromlibrary"] = from_library;
-
- // If full permission object, texture is free to copy,
- // but otherwise we need to check inventory and extract permissions
- //
- // Normally we care only about restrictions for current user and objects
- // don't inherit any 'next owner' permissions from texture, so there is
- // no need to record item id if full_perm==true
- if (!full_perm && !from_library && item_id.notNull())
+ // permissions for overrides
+ // Overrides do not permit no-copy textures
+ LLGLTFMaterial* override = tep->getGLTFMaterialOverride();
+ if (override != nullptr)
{
- LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
- if (itemp)
+ for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
{
- LLPermissions item_permissions = itemp->getPermissions();
- if (item_permissions.allowOperationBy(PERM_COPY,
- gAgent.getID(),
- gAgent.getGroupID()))
+ LLUUID& texture_id = override->mTextureId[i];
+ if (texture_id.notNull())
{
- te_data["te"]["imageitemid"] = item_id;
- te_data["te"]["itemfullperm"] = itemp->getIsFullPerm();
- if (!itemp->isFinished())
- {
- // needed for dropTextureAllFaces
- LLInventoryModelBackgroundFetch::instance().start(item_id, false);
- }
+ const std::string prefix = "pbr" + std::to_string(i);
+ te_data["te"][prefix + "imageid"] = texture_id;
+ set_item_availability(texture_id, te_data["te"], prefix, is_creator, asset_item_map, objectp);
}
}
}
@@ -4201,6 +4357,44 @@ void LLPanelFace::onCopyTexture()
}
}
+bool get_full_permission(const LLSD& te, const std::string &prefix)
+{
+ return te.has(prefix + "itemfullperm") && te[prefix+"itemfullperm"].asBoolean();
+}
+
+bool LLPanelFace::validateInventoryItem(const LLSD& te, const std::string& prefix)
+{
+ if (te.has(prefix + "itemid"))
+ {
+ LLUUID item_id = te[prefix + "itemid"].asUUID();
+ if (item_id.notNull())
+ {
+ LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+ if (!itemp)
+ {
+ // image might be in object's inventory, but it can be not up to date
+ LLSD notif_args;
+ static std::string reason = getString("paste_error_inventory_not_found");
+ notif_args["REASON"] = reason;
+ LLNotificationsUtil::add("FacePasteFailed", notif_args);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // Item was not found on 'copy' stage
+ // Since this happened at copy, might be better to either show this
+ // at copy stage or to drop clipboard here
+ LLSD notif_args;
+ static std::string reason = getString("paste_error_inventory_not_found");
+ notif_args["REASON"] = reason;
+ LLNotificationsUtil::add("FacePasteFailed", notif_args);
+ return false;
+ }
+ return true;
+}
+
void LLPanelFace::onPasteTexture()
{
if (!mClipboardParams.has("texture"))
@@ -4265,39 +4459,49 @@ void LLPanelFace::onPasteTexture()
for (; iter != end; ++iter)
{
const LLSD& te_data = *iter;
- if (te_data.has("te") && te_data["te"].has("imageid"))
+ if (te_data.has("te"))
{
- bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
- full_perm_object &= full_perm;
- if (!full_perm)
+ if (te_data["te"].has("imageid"))
{
- if (te_data["te"].has("imageitemid"))
+ bool full_perm = get_full_permission(te_data["te"], "img");
+ full_perm_object &= full_perm;
+ if (!full_perm)
{
- LLUUID item_id = te_data["te"]["imageitemid"].asUUID();
- if (item_id.notNull())
+ if (!validateInventoryItem(te_data["te"], "img"))
{
- LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
- if (!itemp)
- {
- // image might be in object's inventory, but it can be not up to date
- LLSD notif_args;
- static std::string reason = getString("paste_error_inventory_not_found");
- notif_args["REASON"] = reason;
- LLNotificationsUtil::add("FacePasteFailed", notif_args);
- return;
- }
+ return;
}
}
- else
+ }
+ if (te_data["te"].has("pbr"))
+ {
+ bool full_perm = get_full_permission(te_data["te"], "pbr");
+ full_perm_object &= full_perm;
+ if (!full_perm)
{
- // Item was not found on 'copy' stage
- // Since this happened at copy, might be better to either show this
- // at copy stage or to drop clipboard here
- LLSD notif_args;
- static std::string reason = getString("paste_error_inventory_not_found");
- notif_args["REASON"] = reason;
- LLNotificationsUtil::add("FacePasteFailed", notif_args);
- return;
+ if (!validateInventoryItem(te_data["te"], "pbr"))
+ {
+ return;
+ }
+ }
+ if (te_data["te"].has("pbr_override"))
+ {
+ for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
+ {
+ const std::string prefix = "pbr" + std::to_string(i);
+ if (te_data["te"].has(prefix + "imageid"))
+ {
+ bool full_perm = get_full_permission(te_data["te"], prefix);
+ full_perm_object &= full_perm;
+ if (!full_perm)
+ {
+ if (!validateInventoryItem(te_data["te"], prefix))
+ {
+ return;
+ }
+ }
+ }
+ }
}
}
}
@@ -4322,6 +4526,71 @@ void LLPanelFace::onPasteTexture()
selected_objects->applyToTEs(&navigate_home_func);
}
+void get_item_and_permissions(const LLUUID &id, LLViewerInventoryItem*& itemp, bool& full_perm, bool& from_library, const LLSD &data, const std::string &prefix)
+{
+ full_perm = get_full_permission(data, prefix);
+ from_library = data.has(prefix + "fromlibrary") && data.get(prefix + "fromlibrary").asBoolean();
+ LLViewerInventoryItem* itemp_res = NULL;
+
+ if (data.has(prefix + "itemid"))
+ {
+ LLUUID item_id = data.get(prefix + "itemid").asUUID();
+ if (item_id.notNull())
+ {
+ LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+ if (itemp && itemp->isFinished())
+ {
+ // dropTextureAllFaces will fail if incomplete
+ itemp_res = itemp;
+ }
+ else
+ {
+ // Theoretically shouldn't happend, but if it does happen, we
+ // might need to add a notification to user that paste will fail
+ // since inventory isn't fully loaded
+ LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL;
+ }
+ }
+ }
+
+ // for case when item got removed from inventory after we pressed 'copy'
+ // or texture got pasted into previous object
+ if (!itemp_res && !full_perm)
+ {
+ // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable.
+ LL_INFOS() << "Item " << data.get(prefix + "itemid").asUUID() << " no longer in inventory." << LL_ENDL;
+ // Todo: fix this, we are often searching same texture multiple times (equal to number of faces)
+ // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work
+ LLViewerInventoryCategory::cat_array_t cats;
+ LLViewerInventoryItem::item_array_t items;
+ LLAssetIDMatches asset_id_matches(id);
+ gInventory.collectDescendentsIf(LLUUID::null,
+ cats,
+ items,
+ LLInventoryModel::INCLUDE_TRASH,
+ asset_id_matches);
+
+ // Extremely unreliable and perfomance unfriendly.
+ // But we need this to check permissions and it is how texture control finds items
+ for (S32 i = 0; i < items.size(); i++)
+ {
+ LLViewerInventoryItem* itemp = items[i];
+ if (itemp && itemp->isFinished())
+ {
+ // dropTextureAllFaces will fail if incomplete
+ LLPermissions item_permissions = itemp->getPermissions();
+ if (item_permissions.allowOperationBy(PERM_COPY,
+ gAgent.getID(),
+ gAgent.getGroupID()))
+ {
+ itemp_res = itemp;
+ break; // first match
+ }
+ }
+ }
+ }
+}
+
void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
{
LLSD te_data;
@@ -4345,77 +4614,22 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
if (te_data.has("te"))
{
// Texture
- bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean();
- bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean();
if (te_data["te"].has("imageid"))
{
+ bool img_full_perm = false;
+ bool img_from_library = false;
const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id
- LLViewerInventoryItem* itemp_res = NULL;
+ LLViewerInventoryItem* img_itemp_res = NULL;
- if (te_data["te"].has("imageitemid"))
- {
- LLUUID item_id = te_data["te"]["imageitemid"].asUUID();
- if (item_id.notNull())
- {
- LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
- if (itemp && itemp->isFinished())
- {
- // dropTextureAllFaces will fail if incomplete
- itemp_res = itemp;
- }
- else
- {
- // Theoretically shouldn't happend, but if it does happen, we
- // might need to add a notification to user that paste will fail
- // since inventory isn't fully loaded
- LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL;
- }
- }
- }
- // for case when item got removed from inventory after we pressed 'copy'
- // or texture got pasted into previous object
- if (!itemp_res && !full_perm)
- {
- // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable.
- LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL;
- // Todo: fix this, we are often searching same texture multiple times (equal to number of faces)
- // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLAssetIDMatches asset_id_matches(imageid);
- gInventory.collectDescendentsIf(LLUUID::null,
- cats,
- items,
- LLInventoryModel::INCLUDE_TRASH,
- asset_id_matches);
-
- // Extremely unreliable and perfomance unfriendly.
- // But we need this to check permissions and it is how texture control finds items
- for (S32 i = 0; i < items.size(); i++)
- {
- LLViewerInventoryItem* itemp = items[i];
- if (itemp && itemp->isFinished())
- {
- // dropTextureAllFaces will fail if incomplete
- LLPermissions item_permissions = itemp->getPermissions();
- if (item_permissions.allowOperationBy(PERM_COPY,
- gAgent.getID(),
- gAgent.getGroupID()))
- {
- itemp_res = itemp;
- break; // first match
- }
- }
- }
- }
+ get_item_and_permissions(imageid, img_itemp_res, img_full_perm, img_from_library, te_data["te"], "img");
- if (itemp_res)
+ if (img_itemp_res)
{
if (te == -1) // all faces
{
LLToolDragAndDrop::dropTextureAllFaces(objectp,
- itemp_res,
- from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+ img_itemp_res,
+ img_from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
LLUUID::null,
false);
}
@@ -4423,15 +4637,15 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
{
LLToolDragAndDrop::dropTextureOneFace(objectp,
te,
- itemp_res,
- from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+ img_itemp_res,
+ img_from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
LLUUID::null,
false,
0);
}
}
// not an inventory item or no complete items
- else if (full_perm)
+ else if (img_full_perm)
{
// Either library, local or existed as fullperm when user made a copy
LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
@@ -4459,17 +4673,65 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
// PBR/GLTF
if (te_data["te"].has("pbr"))
{
- objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false /*managing our own update*/);
- tep->setGLTFRenderMaterial(nullptr);
- tep->setGLTFMaterialOverride(nullptr);
+ const LLUUID pbr_id = te_data["te"]["pbr"].asUUID();
+ bool pbr_full_perm = false;
+ bool pbr_from_library = false;
+ LLViewerInventoryItem* pbr_itemp_res = NULL;
+
+ get_item_and_permissions(pbr_id, pbr_itemp_res, pbr_full_perm, pbr_from_library, te_data["te"], "pbr");
+ bool allow = true;
+
+ // check overrides first since they don't need t be moved to inventory
if (te_data["te"].has("pbr_override"))
{
- LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID(), te_data["te"]["pbr_override"]);
+ for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
+ {
+ const std::string prefix = "pbr" + std::to_string(i);
+ if (te_data["te"].has(prefix + "imageid"))
+ {
+ LLUUID tex_id = te_data["te"][prefix + "imageid"];
+
+ bool full_perm = false;
+ bool from_library = false;
+ LLViewerInventoryItem* itemp_res = NULL;
+ get_item_and_permissions(tex_id, itemp_res, full_perm, from_library, te_data["te"], prefix);
+ allow = full_perm;
+ if (!allow) break;
+ }
+ }
}
- else
+
+ if (allow && pbr_itemp_res)
+ {
+ if (pbr_itemp_res)
+ {
+ allow = LLToolDragAndDrop::handleDropMaterialProtections(
+ objectp,
+ pbr_itemp_res,
+ pbr_from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+ pbr_id);
+ }
+ else
+ {
+ allow = pbr_full_perm;
+ }
+ }
+
+ if (allow)
{
- LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID());
+ objectp->setRenderMaterialID(te, te_data["te"]["pbr"].asUUID(), false /*managing our own update*/);
+ tep->setGLTFRenderMaterial(nullptr);
+ tep->setGLTFMaterialOverride(nullptr);
+
+ if (te_data["te"].has("pbr_override"))
+ {
+ LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID(), te_data["te"]["pbr_override"]);
+ }
+ else
+ {
+ LLGLTFMaterialList::queueApply(objectp, te, te_data["te"]["pbr"].asUUID());
+ }
}
}
else
@@ -4642,6 +4904,29 @@ void LLPanelFace::updateGLTFTextureTransform(std::function<void(LLGLTFMaterial::
}
}
+void LLPanelFace::updateGLTFTextureTransformWithScale(const LLGLTFMaterial::TextureInfo texture_info, std::function<void(LLGLTFMaterial::TextureTransform*, const F32, const F32)> edit)
+{
+ if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT)
+ {
+ updateSelectedGLTFMaterialsWithScale([&](LLGLTFMaterial* new_override, const F32 scale_s, const F32 scale_t)
+ {
+ for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
+ {
+ LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[(LLGLTFMaterial::TextureInfo)i];
+ edit(&new_transform, scale_s, scale_t);
+ }
+ });
+ }
+ else
+ {
+ updateSelectedGLTFMaterialsWithScale([&](LLGLTFMaterial* new_override, const F32 scale_s, const F32 scale_t)
+ {
+ LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[texture_info];
+ edit(&new_transform, scale_s, scale_t);
+ });
+ }
+}
+
void LLPanelFace::setMaterialOverridesFromSelection()
{
const LLGLTFMaterial::TextureInfo texture_info = getPBRTextureInfo();
@@ -4717,8 +5002,9 @@ void LLPanelFace::setMaterialOverridesFromSelection()
}
}
- mPBRScaleU->setValue(transform.mScale[VX]);
- mPBRScaleV->setValue(transform.mScale[VY]);
+ // Force set scales just in case they were set by repeats per meter and their spinner is focused
+ mPBRScaleU->forceSetValue(transform.mScale[VX]);
+ mPBRScaleV->forceSetValue(transform.mScale[VY]);
mPBRRotate->setValue(transform.mRotation * RAD_TO_DEG);
mPBROffsetU->setValue(transform.mOffset[VX]);
mPBROffsetV->setValue(transform.mOffset[VY]);
@@ -4728,6 +5014,12 @@ void LLPanelFace::setMaterialOverridesFromSelection()
mPBRRotate->setTentative(!rotation_same);
mPBROffsetU->setTentative(!offset_u_same);
mPBROffsetV->setTentative(!offset_v_same);
+
+ F32 repeats = 1.f;
+ bool identical = false;
+ getSelectedGLTFMaterialMaxRepeats(getPBRDropChannel(), repeats, identical);
+ mPBRRepeat->forceSetValue(repeats);
+ mPBRRepeat->setTentative(!identical || !scale_u_same || !scale_v_same);
}
void LLPanelFace::Selection::connect()
@@ -5151,6 +5443,7 @@ void LLPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool
LLMaterial* mat = object->getTE(face)->getMaterialParams().get();
U32 s_axis = VX;
U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
F32 repeats_s = 1.0f;
F32 repeats_t = 1.0f;
if (mat)
@@ -5175,6 +5468,7 @@ void LLPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool&
LLMaterial* mat = object->getTE(face)->getMaterialParams().get();
U32 s_axis = VX;
U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
F32 repeats_s = 1.0f;
F32 repeats_t = 1.0f;
if (mat)
@@ -5219,6 +5513,62 @@ void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_a
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
}
+void LLPanelFace::LLSelectedTEMaterial::selectionNormalScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter)
+{
+ struct f : public LLSelectedTEFunctor
+ {
+ LLPanelFace* mFacePanel;
+ F32 mRepeatsPerMeter;
+ f(LLPanelFace* face_panel, const F32& repeats_per_meter) : mFacePanel(face_panel), mRepeatsPerMeter(repeats_per_meter) {}
+ bool apply(LLViewerObject* object, S32 te)
+ {
+ if (object->permModify())
+ {
+ // Compute S,T to axis mapping
+ U32 s_axis, t_axis;
+ if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
+ return true;
+
+ F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
+ F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
+
+ setNormalRepeatX(mFacePanel, new_s, te);
+ setNormalRepeatY(mFacePanel, new_t, te);
+ }
+ return true;
+ }
+ } setfunc(panel_face, repeats_per_meter);
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+}
+
+void LLPanelFace::LLSelectedTEMaterial::selectionSpecularScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter)
+{
+ struct f : public LLSelectedTEFunctor
+ {
+ LLPanelFace* mFacePanel;
+ F32 mRepeatsPerMeter;
+ f(LLPanelFace* face_panel, const F32& repeats_per_meter) : mFacePanel(face_panel), mRepeatsPerMeter(repeats_per_meter) {}
+ bool apply(LLViewerObject* object, S32 te)
+ {
+ if (object->permModify())
+ {
+ // Compute S,T to axis mapping
+ U32 s_axis, t_axis;
+ if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
+ return true;
+
+ F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
+ F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
+
+ setSpecularRepeatX(mFacePanel, new_s, te);
+ setSpecularRepeatY(mFacePanel, new_t, te);
+ }
+ return true;
+ }
+ } setfunc(panel_face, repeats_per_meter);
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+}
+
void LLPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical)
{
struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>