diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 61a713f25d..b3b28045b8 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -152,6 +152,7 @@ set(viewer_SOURCE_FILES
fsnearbychatvoicemonitor.cpp
fspanelblocklist.cpp
fspanelcontactsets.cpp
+ fspanelface.cpp
fspanelimcontrolpanel.cpp
fspanellogin.cpp
fspanelprefs.cpp
@@ -944,6 +945,7 @@ set(viewer_HEADER_FILES
fsnearbychatvoicemonitor.h
fspanelblocklist.h
fspanelcontactsets.h
+ fspanelface.h
fspanelimcontrolpanel.h
fspanellogin.h
fspanelprefs.h
diff --git a/indra/newview/app_settings/graphic_preset_controls.xml b/indra/newview/app_settings/graphic_preset_controls.xml
index 87c653c43a..4cdf8e94c3 100644
--- a/indra/newview/app_settings/graphic_preset_controls.xml
+++ b/indra/newview/app_settings/graphic_preset_controls.xml
@@ -19,29 +19,55 @@
RenderAvatarMaxComplexity
RenderAvatarMaxNonImpostors
RenderAvatarPhysicsLODFactor
+ RenderCloudShadowAmbianceFactor
RenderCompressTextures
RenderDeferredSSAO
RenderDepthOfField
RenderDepthOfFieldInEditMode
+ RenderDisablePostProcessing
+ RenderPostProcessingHDR
+ RenderDefaultProbeUpdatePeriod
RenderDynamicExposureCoefficient
RenderExposure
RenderFarClip
RenderFlexTimeFactor
RenderFSAASamples
RenderGlow
+ RenderGlowHDR
RenderGlowIterations
+ RenderGlowNoise
RenderGlowResolutionPow
RenderLocalLightCount
RenderMaxPartCount
+ RenderMaxVRAMBudget
RenderQualityPerformance
RenderReflectionsEnabled
+ RenderReflectionProbeAmbiance
RenderReflectionProbeDetail
+ RenderReflectionProbeDrawDistance
RenderReflectionProbeLevel
+ RenderReflectionProbeMaxLocalLightAmbiance
+ RenderReflectionProbeResolution
+ RenderReflectionProbeVolumes
RenderScreenSpaceReflections
+ RenderScreenSpaceReflectionIterations
+ RenderScreenSpaceReflectionRayStep
+ RenderScreenSpaceReflectionDistanceBias
+ RenderScreenSpaceReflectionDepthRejectBias
+ RenderScreenSpaceReflectionAdaptiveStepMultiplier
+ RenderScreenSpaceReflectionGlossySamples
RenderShaderLightingMaxLevel
RenderShadowDetail
RenderShadowResolutionScale
+ RenderSkyAmbientScale
+ RenderSkyAutoAdjustAmbientScale
+ RenderSkyAutoAdjustBlueDensityScale
+ RenderSkyAutoAdjustBlueHorizonScale
+ RenderSkyAutoAdjustSunColorScale
+ RenderSkyAutoAdjustHDRScale
RenderSkyAutoAdjustLegacy
+ RenderSkyAutoAdjustProbeAmbiance
+ RenderSkySunlightScale
RenderSSAOIrradianceScale
RenderSSAOIrradianceMax
RenderSunDynamicRange
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 3655ba6b32..eff7cf9c5e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -13580,7 +13580,7 @@ Change of this parameter will affect the layout of buttons in notification toast
Value
1.0
- RendeSkyAutoAdjustBlueHorizonScale
+ RenderSkyAutoAdjustBlueHorizonScale
- RendeSkyAutoAdjustBlueDensityScale
+ RenderSkyAutoAdjustBlueDensityScale
+ FSShowSelectedInBlinnPhong
+
ShowSpecificLODInEdit
-
+ FSUseNewTexturePanel
+
+ FSInternalCanEditObjectFaces
+
+ FSInternalFaceHasBPNormalMap
+
+ FSInternalFaceHasBPSpecularMap
+
+
diff --git a/indra/newview/fspanelface.cpp b/indra/newview/fspanelface.cpp
new file mode 100644
index 0000000000..8e714cc9c9
--- /dev/null
+++ b/indra/newview/fspanelface.cpp
@@ -0,0 +1,5982 @@
+/**
+ * @file fspanelface.cpp
+ * @brief Consolidated materials/texture panel in the tools floater
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2024, Zi Ree@Second Life
+ *
+ * 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 "fspanelface.h"
+
+#include // Used to find all faces with same texture
+
+#include "llagent.h"
+#include "llagentdata.h"
+#include "llbutton.h"
+#include "llcalc.h"
+#include "llcheckboxctrl.h"
+#include "llcolorswatch.h"
+#include "llcombobox.h"
+#include "lldrawpoolbump.h"
+#include "llerror.h"
+#include "llface.h"
+// #include "llfilesystem.h"
+#include "llfetchedgltfmaterial.h"
+#include "llgltfmateriallist.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h" // gInventory
+#include "llinventorymodelbackgroundfetch.h"
+#include "llfloatermediasettings.h"
+#include "llfloaterreg.h"
+#include "llfloatertools.h"
+#include "llfontgl.h"
+#include "lllineeditor.h"
+#include "llmaterialmgr.h"
+#include "llmaterialeditor.h"
+#include "llmediactrl.h"
+#include "llmediaentry.h"
+#include "llmenubutton.h"
+#include "llnotificationsutil.h"
+#include "llpanelcontents.h"
+#include "llpluginclassmedia.h"
+#include "llradiogroup.h"
+#include "llrect.h"
+#include "llresmgr.h"
+// #include "llsd.h"
+// #include "llsdserialize.h"
+// #include "llsdutil.h"
+#include "llselectmgr.h"
+#include "llspinctrl.h"
+#include "llstring.h"
+#include "lltextbox.h"
+#include "lltexturectrl.h"
+#include "lltextureentry.h"
+#include "lltooldraganddrop.h"
+#include "lltoolface.h"
+#include "lltoolmgr.h"
+#include "lltrans.h"
+#include "llui.h"
+// #include "llviewerassetupload.h"
+#include "llviewercontrol.h"
+#include "llviewermedia.h"
+// #include "llviewermenufile.h"
+#include "llviewerobject.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llvovolume.h"
+#include "llvoinventorylistener.h"
+#include "lluictrlfactory.h"
+#include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI
+
+// Dirty flags - taken from llmaterialeditor.cpp ... LL please put this in a .h! -Zi
+static const U32 MATERIAL_BASE_COLOR_DIRTY = 0x1 << 0;
+static const U32 MATERIAL_BASE_COLOR_TEX_DIRTY = 0x1 << 1;
+
+static const U32 MATERIAL_NORMAL_TEX_DIRTY = 0x1 << 2;
+
+static const U32 MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY = 0x1 << 3;
+static const U32 MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY = 0x1 << 4;
+static const U32 MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY = 0x1 << 5;
+
+static const U32 MATERIAL_EMISIVE_COLOR_DIRTY = 0x1 << 6;
+static const U32 MATERIAL_EMISIVE_TEX_DIRTY = 0x1 << 7;
+
+static const U32 MATERIAL_DOUBLE_SIDED_DIRTY = 0x1 << 8;
+static const U32 MATERIAL_ALPHA_MODE_DIRTY = 0x1 << 9;
+static const U32 MATERIAL_ALPHA_CUTOFF_DIRTY = 0x1 << 10;
+
+FSPanelFace::Selection FSPanelFace::sMaterialOverrideSelection;
+
+void FSPanelFace::updateSelectedGLTFMaterials(std::function func)
+{
+ struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor
+ {
+ LLSelectedTEGLTFMaterialFunctor(std::function 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();
+ }
+ mFunc(&new_override);
+ LLGLTFMaterialList::queueModify(object, face, &new_override);
+
+ return true;
+ }
+
+ std::function mFunc;
+ } select_func(func);
+
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
+}
+
+template
+void readSelectedGLTFMaterial(std::function func, T& value, bool& identical, bool has_tolerance, T tolerance)
+{
+ struct LLSelectedTEGetGLTFMaterialFunctor : public LLSelectedTEGetFunctor
+ {
+ LLSelectedTEGetGLTFMaterialFunctor(std::function func) : mFunc(func) {}
+ virtual ~LLSelectedTEGetGLTFMaterialFunctor() {};
+ T get(LLViewerObject* object, S32 face) override
+ {
+ const LLTextureEntry* tep = object->getTE(face);
+ const LLGLTFMaterial* render_material = tep->getGLTFRenderMaterial();
+
+ return mFunc(render_material);
+ }
+
+ std::function mFunc;
+ } select_func(func);
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance);
+}
+
+//
+// keep LLRenderMaterialFunctor in sync with llmaterialeditor.cpp - Would be nice if we
+// had this in its own file so we could include it from both sides ... -Zi
+//
+
+// local preview of material changes
+class LLRenderMaterialFunctor : public LLSelectedTEFunctor
+{
+public:
+ LLRenderMaterialFunctor(const LLUUID &id)
+ : mMatId(id)
+ {
+ }
+
+ bool apply(LLViewerObject* objectp, S32 te) override
+ {
+ if (objectp && objectp->permModify() && objectp->getVolume())
+ {
+ LLVOVolume* vobjp = (LLVOVolume*)objectp;
+ vobjp->setRenderMaterialID(te, mMatId, false /*preview only*/);
+ vobjp->updateTEMaterialTextures(te);
+ }
+ return true;
+ }
+private:
+ LLUUID mMatId;
+};
+
+//
+// keep LLRenderMaterialOverrideFunctor in sync with llmaterialeditor.cpp just take
+// out the reverting functionality as it makes no real sense with all the texture
+// controls visible for the material at all times.
+// TODO: look at how to handle local textures, especially when saving materials
+// - Would be nice if we had this in its own file so we could include it from both sides ... -Zi
+//
+class LLRenderMaterialOverrideFunctor : public LLSelectedNodeFunctor
+{
+public:
+ LLRenderMaterialOverrideFunctor(
+ LLGLTFMaterial* material_to_apply,
+ U32 unsaved_changes
+ )
+ : mMaterialToApply(material_to_apply)
+ , mUnsavedChanges(unsaved_changes)
+ {
+ }
+
+ virtual bool apply(LLSelectNode* nodep) override
+ {
+ LLViewerObject* objectp = nodep->getObject();
+ if (!objectp || !objectp->permModify() || !objectp->getVolume())
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << 10001 << " skipped object" << LL_ENDL;
+ return false;
+ }
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); // avatars have TEs but no faces
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << 10002 << " " << num_tes << LL_ENDL;
+
+ // post override from given object and te to the simulator
+ // requestData should have:
+ // object_id - UUID of LLViewerObject
+ // side - S32 index of texture entry
+ // gltf_json - String of GLTF json for override data
+
+ for (S32 te = 0; te < num_tes; ++te)
+ {
+ if (!nodep->isTESelected(te))
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << 10003 << " skipping unselected te " << te << LL_ENDL;
+ continue;
+ }
+
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << 10004 << " te " << te << LL_ENDL;
+ // Get material from object
+ // Selection can cover multiple objects, and live editor is
+ // supposed to overwrite changed values only
+ LLTextureEntry* tep = objectp->getTE(te);
+
+ if (tep->getGLTFMaterial() == nullptr)
+ {
+ // overrides are not supposed to work or apply if
+ // there is no base material to work from
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << 10004 << " skipping te with no base material " << te << LL_ENDL;
+ continue;
+ }
+
+ LLPointer material = tep->getGLTFMaterialOverride();
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "10004b" << " material is null? " << material.isNull() << LL_ENDL;
+ // make a copy to not invalidate existing
+ // material for multiple objects
+ if (material.isNull())
+ {
+ // Start with a material override which does not make any changes
+ material = new LLGLTFMaterial();
+ }
+ else
+ {
+ material = new LLGLTFMaterial(*material);
+ }
+
+ // Override object's values with values from editor where appropriate
+ if (mUnsavedChanges & MATERIAL_BASE_COLOR_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_BASE_COLOR_DIRTY" << LL_ENDL;
+ material->setBaseColorFactor(mMaterialToApply->mBaseColor, true);
+ }
+
+ if (mUnsavedChanges & MATERIAL_BASE_COLOR_TEX_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_BASE_COLOR_TEX_DIRTY" << LL_ENDL;
+ material->setBaseColorId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR], true);
+ /*
+ LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_BASE_COLOR_TEX_DIRTY);
+ if (tracking_id.notNull())
+ {
+ LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material);
+ }
+ */
+ }
+
+ if (mUnsavedChanges & MATERIAL_NORMAL_TEX_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_NORMAL_TEX_DIRTY" << LL_ENDL;
+ material->setNormalId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL], true);
+ /*
+ LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_NORMAL_TEX_DIRTY);
+ if (tracking_id.notNull())
+ {
+ LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material);
+ }
+ */
+ }
+
+ if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY" << LL_ENDL;
+ material->setOcclusionRoughnessMetallicId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS], true);
+ /*
+ LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY);
+ if (tracking_id.notNull())
+ {
+ LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material);
+ }
+ */
+ }
+
+ if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY" << LL_ENDL;
+ material->setMetallicFactor(mMaterialToApply->mMetallicFactor, true);
+ }
+
+ if (mUnsavedChanges & MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY" << LL_ENDL;
+ material->setRoughnessFactor(mMaterialToApply->mRoughnessFactor, true);
+ }
+
+ if (mUnsavedChanges & MATERIAL_EMISIVE_COLOR_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_EMISIVE_COLOR_DIRTY" << LL_ENDL;
+ material->setEmissiveColorFactor(LLColor3(mMaterialToApply->mEmissiveColor), true);
+ }
+
+ if (mUnsavedChanges & MATERIAL_EMISIVE_TEX_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_EMISIVE_TEX_DIRTY" << LL_ENDL;
+ material->setEmissiveId(mMaterialToApply->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE], true);
+ /*
+ LLUUID tracking_id = mEditor->getLocalTextureTrackingIdFromFlag(MATERIAL_EMISIVE_TEX_DIRTY);
+ if (tracking_id.notNull())
+ {
+ LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(tracking_id, material);
+ }
+ */
+ }
+
+ if (mUnsavedChanges & MATERIAL_DOUBLE_SIDED_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_DOUBLE_SIDED_DIRTY" << LL_ENDL;
+ material->setDoubleSided(mMaterialToApply->mDoubleSided, true);
+ }
+
+ if (mUnsavedChanges & MATERIAL_ALPHA_MODE_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_ALPHA_MODE_DIRTY" << LL_ENDL;
+ material->setAlphaMode(mMaterialToApply->mAlphaMode, true);
+ }
+
+ if (mUnsavedChanges & MATERIAL_ALPHA_CUTOFF_DIRTY)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "appyling MATERIAL_ALPHA_CUTOFF_DIRTY" << LL_ENDL;
+ material->setAlphaCutoff(mMaterialToApply->mAlphaCutoff, true);
+ }
+
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << 10100 << " queueing material update " << te << LL_ENDL;
+ LLGLTFMaterialList::queueModify(objectp, te, material);
+ }
+ return true;
+ }
+
+private:
+ LLGLTFMaterial* mMaterialToApply;
+ U32 mUnsavedChanges;
+};
+
+//
+// Get all material parameters
+//
+struct LLSelectedTEGetmatId : public LLSelectedTEFunctor
+{
+ LLSelectedTEGetmatId() :
+ mHasFacesWithoutPBR(false),
+ mHasFacesWithPBR(false),
+ mInitialized(false),
+ mMaterial(nullptr)
+ {
+ }
+
+ bool apply(LLViewerObject* object, S32 te_index) override
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "object " << object << " te_index " << te_index << LL_ENDL;
+ LLUUID pbr_id = object->getRenderMaterialID(te_index);
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000000 << " Material: " << pbr_id << LL_ENDL;
+
+ if (pbr_id.isNull())
+ {
+ mHasFacesWithoutPBR = true;
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000001 << LL_ENDL;
+ return false;
+ }
+
+ mHasFacesWithPBR = true;
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000002 << LL_ENDL;
+
+ if (mInitialized)
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000003 << LL_ENDL;
+ if (mMaterialId != pbr_id)
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000004 << LL_ENDL;
+ mIdenticalMaterial = false;
+ }
+
+ LLGLTFMaterial* te_mat = object->getTE(te_index)->getGLTFMaterial();
+ LLGLTFMaterial* te_override = object->getTE(te_index)->getGLTFMaterialOverride();
+
+ // copy base material values to the override material, so we can apply the override to it in the next steps
+ if (te_mat)
+ {
+ mMaterialOverride = *te_mat;
+ }
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000005 << " te_override:" << te_override << LL_ENDL;
+ for(U32 map = 0; map < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; map++)
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000009 << " map:" << map << LL_ENDL;
+
+ LLUUID texture_map_id;
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000018 << "te_mat:" << te_mat << " mMaterialOverride.mTextureId[map]:" << mMaterialOverride.mTextureId[map] << LL_ENDL;
+ texture_map_id = mMaterialOverride.mTextureId[map];
+
+ if (te_override)
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000018b" << " te_override->mTextureId[map]:" << te_override->mTextureId[map] << LL_ENDL;
+ if (te_override->mTextureId[map].notNull())
+ {
+ texture_map_id = te_override->mTextureId[map];
+ if (texture_map_id == LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID)
+ {
+ texture_map_id.setNull();
+ }
+ }
+ }
+
+ if (texture_map_id != mMaterialSummary.mTextureId[map])
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000018 << " mIdenticalMap[" << map << "]: false" << LL_ENDL;
+ mIdenticalMap[map] = false;
+ }
+ }
+
+ if (te_override)
+ {
+ // copy values from base material to the override where the override has defaults
+ if (te_override->mBaseColor == LLGLTFMaterial::getDefaultBaseColor()) mMaterialOverride.mBaseColor = te_mat->mBaseColor;
+ if (te_override->mMetallicFactor == LLGLTFMaterial::getDefaultMetallicFactor()) mMaterialOverride.mMetallicFactor = te_mat->mMetallicFactor;
+ if (te_override->mRoughnessFactor == LLGLTFMaterial::getDefaultRoughnessFactor()) mMaterialOverride.mRoughnessFactor = te_mat->mRoughnessFactor;
+ if (te_override->mEmissiveColor == LLGLTFMaterial::getDefaultEmissiveColor()) mMaterialOverride.mEmissiveColor = te_mat->mEmissiveColor;
+ if (te_override->mDoubleSided == LLGLTFMaterial::getDefaultDoubleSided()) mMaterialOverride.mDoubleSided = te_mat->mDoubleSided;
+ if (te_override->mAlphaMode == LLGLTFMaterial::getDefaultAlphaMode()) mMaterialOverride.mAlphaMode = te_mat->mAlphaMode;
+ if (te_override->mAlphaCutoff == LLGLTFMaterial::getDefaultAlphaCutoff()) mMaterialOverride.mAlphaCutoff = te_mat->mAlphaCutoff;
+ }
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000018c" << " te_mat->mEmissiveColor:" << te_mat->mEmissiveColor << LL_ENDL;
+
+ if (mMaterialOverride.mBaseColor != mMaterialSummary.mBaseColor) mIdenticalBaseColor = false;
+ if (mMaterialOverride.mMetallicFactor != mMaterialSummary.mMetallicFactor) mIdenticalMetallic = false;
+ if (mMaterialOverride.mRoughnessFactor != mMaterialSummary.mRoughnessFactor) mIdenticalRoughness = false;
+ if (mMaterialOverride.mEmissiveColor != mMaterialSummary.mEmissiveColor) mIdenticalEmissive = false;
+ if (mMaterialOverride.mDoubleSided != mMaterialSummary.mDoubleSided) mIdenticalDoubleSided = false;
+ if (mMaterialOverride.mAlphaMode != mMaterialSummary.mAlphaMode) mIdenticalAlphaMode = false;
+ if (mMaterialOverride.mAlphaCutoff != mMaterialSummary.mAlphaCutoff) mIdenticalAlphaCutoff = false;
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000011 << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000012 << LL_ENDL;
+
+ mIdenticalMaterial = true;
+ mIdenticalBaseColor = true;
+ mIdenticalMetallic = true;
+ mIdenticalRoughness = true;
+ mIdenticalEmissive = true;
+ mIdenticalDoubleSided = true;
+ mIdenticalAlphaMode = true;
+ mIdenticalAlphaCutoff = true;
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000013 << LL_ENDL;
+
+ LLGLTFMaterial* mat = object->getTE(te_index)->getGLTFMaterial();
+ LLGLTFMaterial* override = object->getTE(te_index)->getGLTFMaterialOverride();
+
+ mMaterialId = pbr_id;
+ mMaterial = override;
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000014 << " override:" << override << LL_ENDL;
+
+ // copy base material values to the "summary" material, so we can apply the override to it in the next step
+ if (mat)
+ {
+ mMaterialSummary = *mat;
+ }
+
+ for(U32 map = 0; map < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; map++)
+ {
+ // initialize array to say "all PBR maps are the same"
+ mIdenticalMap[map] = true;
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << 10000017 << " map:" << map << LL_ENDL;
+
+ if (override && override->mTextureId[map].notNull())
+ {
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS") << "10000017b" << " override->mTextureId[map]:" << override->mTextureId[map] << LL_ENDL;
+ if (override->mTextureId[map] == LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID)
+ {
+ mMaterialSummary.mTextureId[map].setNull();
+ }
+ else
+ {
+ mMaterialSummary.mTextureId[map] = override->mTextureId[map];
+ }
+ }
+ }
+
+ if (override)
+ {
+ // copy values from override to the "summary" material where the override differs from the default
+ if (override->mBaseColor != LLGLTFMaterial::getDefaultBaseColor()) mMaterialSummary.mBaseColor = override->mBaseColor;
+ if (override->mMetallicFactor != LLGLTFMaterial::getDefaultMetallicFactor()) mMaterialSummary.mMetallicFactor = override->mMetallicFactor;
+ if (override->mRoughnessFactor != LLGLTFMaterial::getDefaultRoughnessFactor()) mMaterialSummary.mRoughnessFactor = override->mRoughnessFactor;
+ if (override->mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor()) mMaterialSummary.mEmissiveColor = override->mEmissiveColor;
+ if (override->mDoubleSided != LLGLTFMaterial::getDefaultDoubleSided()) mMaterialSummary.mDoubleSided = override->mDoubleSided;
+ if (override->mAlphaMode != LLGLTFMaterial::getDefaultAlphaMode()) mMaterialSummary.setAlphaMode(override->getAlphaMode());
+ if (override->mAlphaCutoff != LLGLTFMaterial::getDefaultAlphaCutoff()) mMaterialSummary.mAlphaCutoff = override->mAlphaCutoff;
+ }
+
+ mInitialized = true;
+ }
+
+ return true;
+ }
+
+ bool mHasFacesWithoutPBR;
+ bool mHasFacesWithPBR;
+ bool mInitialized;
+
+ LLGLTFMaterial* mMaterial;
+ LLGLTFMaterial mMaterialOverride;
+ LLGLTFMaterial mMaterialSummary;
+
+ bool mIdenticalMaterial;
+
+ bool mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT];
+ bool mIdenticalBaseColor;
+ bool mIdenticalMetallic;
+ bool mIdenticalRoughness;
+ bool mIdenticalEmissive;
+ bool mIdenticalDoubleSided;
+ bool mIdenticalAlphaMode;
+ bool mIdenticalAlphaCutoff;
+
+ LLUUID mMaterialId;
+};
+
+//
+// "Use texture" label for normal/specular type comboboxes
+// Filled in at initialization from translated strings
+//
+std::string USE_TEXTURE_LABEL; // subtly different (and more clear) name from llpanelface.cpp to avoid clashes -Zi
+
+FSPanelFace::FSPanelFace() :
+ LLPanel(),
+ mNeedMediaTitle(true),
+ mUnsavedChanges(0)
+{
+ // register callbacks before buildFromFile() or they won't work!
+ mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&FSPanelFace::onCommitFlip, this, _2));
+ mCommitCallbackRegistrar.add("BuildTool.GLTFUVSpinner", boost::bind(&FSPanelFace::onCommitGLTFUVSpinner, this, _1, _2));
+ mCommitCallbackRegistrar.add("BuildTool.SelectSameTexture", boost::bind(&FSPanelFace::onClickBtnSelectSameTexture, this, _1, _2));
+ mCommitCallbackRegistrar.add("BuildTool.ShowFindAllButton", boost::bind(&FSPanelFace::onShowFindAllButton, this, _1, _2));
+ mCommitCallbackRegistrar.add("BuildTool.HideFindAllButton", boost::bind(&FSPanelFace::onHideFindAllButton, this, _1, _2));
+
+ buildFromFile("panel_fs_tools_texture.xml");
+
+ USE_TEXTURE_LABEL = LLTrans::getString("use_texture");
+}
+
+FSPanelFace::~FSPanelFace()
+{
+ unloadMedia();
+}
+
+//
+// Methods
+//
+
+// make sure all referenced UI controls are actually present in the skin
+// and if not, terminate immediately with the line number of the error,
+// so the skin creator will be alerted that something is wrong, and the
+// rest of the code can assume all UI controls are actually there -Zi
+#define SKIN_CHECK(x) if ( !(x) ) { skin_error(__LINE__); }
+
+void skin_error(int line)
+{
+ LL_ERRS("BuildTool") << "Skin error in line: " << line << LL_ENDL;
+}
+
+void FSPanelFace::onMatTabChange()
+{
+ static S32 last_mat = -1;
+ if( auto curr_mat = getCurrentMaterialType(); curr_mat != last_mat )
+ {
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ LLViewerObject* objectp = node ? node->getObject() : NULL;
+ if(objectp)
+ {
+ last_mat = curr_mat;
+ gSavedSettings.setBOOL("FSShowSelectedInBlinnPhong", (curr_mat == MATMEDIA_MATERIAL));
+ objectp->markForUpdate();
+ objectp->faceMappingChanged();
+ }
+ }
+}
+
+BOOL FSPanelFace::postBuild()
+{
+ //
+ // grab pointers to all relevant UI elements here and verify they are good
+ //
+
+ // Tab controls
+ SKIN_CHECK(mTabsPBRMatMedia = findChild("tabs_material_type"));
+ SKIN_CHECK(mTabsMatChannel = findChild("tabs_blinn_phong_uvs"));
+ SKIN_CHECK(mTabsPBRChannel = findChild("tabs_pbr_transforms"));
+
+ // common controls and parameters for Blinn-Phong and PBR
+ SKIN_CHECK(mBtnCopyFaces = findChild("copy_face_btn"));
+ SKIN_CHECK(mBtnPasteFaces = findChild("paste_face_btn"));
+ SKIN_CHECK(mCtrlGlow = findChild("glow"));
+ SKIN_CHECK(mCtrlRpt = findChild("rptctrl"));
+
+ // Blinn-Phong alpha parameters
+ SKIN_CHECK(mCtrlColorTransp = findChild("ColorTrans"));
+ SKIN_CHECK(mColorTransPercent = findChild("color trans percent"));
+ SKIN_CHECK(mLabelAlphaMode = findChild("label alphamode"));
+ SKIN_CHECK(mComboAlphaMode = findChild("combobox alphamode"));
+ SKIN_CHECK(mCtrlMaskCutoff = findChild("maskcutoff"));
+ SKIN_CHECK(mCheckFullbright = findChild("checkbox fullbright"));
+
+ // Blinn-Phong texture transforms and controls
+ SKIN_CHECK(mLabelTexGen = findChild("tex gen"));
+ SKIN_CHECK(mComboTexGen = findChild("combobox texgen"));
+ SKIN_CHECK(mCheckPlanarAlign = findChild("checkbox planar align"));
+ SKIN_CHECK(mLabelBumpiness = findChild("label bumpiness"));
+ SKIN_CHECK(mComboBumpiness = findChild("combobox bumpiness"));
+ SKIN_CHECK(mLabelShininess = findChild("label shininess"));
+ SKIN_CHECK(mComboShininess = findChild("combobox shininess"));
+ SKIN_CHECK(mCtrlTexScaleU = findChild("TexScaleU"));
+ SKIN_CHECK(mCtrlTexScaleV = findChild("TexScaleV"));
+ SKIN_CHECK(mCtrlTexOffsetU = findChild("TexOffsetU"));
+ SKIN_CHECK(mCtrlTexOffsetV = findChild("TexOffsetV"));
+ SKIN_CHECK(mCtrlTexRot = findChild("TexRot"));
+ SKIN_CHECK(mCtrlBumpyScaleU = findChild("bumpyScaleU"));
+ SKIN_CHECK(mCtrlBumpyScaleV = findChild("bumpyScaleV"));
+ SKIN_CHECK(mCtrlBumpyOffsetU = findChild("bumpyOffsetU"));
+ SKIN_CHECK(mCtrlBumpyOffsetV = findChild("bumpyOffsetV"));
+ SKIN_CHECK(mCtrlBumpyRot = findChild("bumpyRot"));
+ SKIN_CHECK(mCtrlShinyScaleU = findChild("shinyScaleU"));
+ SKIN_CHECK(mCtrlShinyScaleV = findChild("shinyScaleV"));
+ SKIN_CHECK(mCtrlShinyOffsetU = findChild("shinyOffsetU"));
+ SKIN_CHECK(mCtrlShinyOffsetV = findChild("shinyOffsetV"));
+ SKIN_CHECK(mCtrlShinyRot = findChild("shinyRot"));
+ SKIN_CHECK(mCtrlGlossiness = findChild("glossiness"));
+ SKIN_CHECK(mCtrlEnvironment = findChild("environment"));
+
+ // Blinn-Phong Diffuse tint color swatch
+ SKIN_CHECK(mColorSwatch = findChild("colorswatch"));
+
+ // Blinn-Phong Diffuse texture swatch
+ SKIN_CHECK(mTextureCtrl = findChild("texture control"));
+
+ // Blinn-Phong Normal texture swatch
+ SKIN_CHECK(mBumpyTextureCtrl = findChild("bumpytexture control"));
+
+ // Blinn-Phong Specular texture swatch
+ SKIN_CHECK(mShinyTextureCtrl = findChild("shinytexture control"));
+
+ // Blinn-Phong Specular tint color swatch
+ SKIN_CHECK(mShinyColorSwatch = findChild("shinycolorswatch"));
+
+ // Texture alignment and maps synchronization
+ SKIN_CHECK(mBtnAlignMedia = findChild("button align"));
+ SKIN_CHECK(mBtnAlignTextures = findChild("button align textures"));
+ SKIN_CHECK(mCheckSyncMaterials = findChild("checkbox_sync_settings"))
+
+ // Media
+ SKIN_CHECK(mBtnDeleteMedia = findChild("delete_media"));
+ SKIN_CHECK(mBtnAddMedia = findChild("add_media"));
+ SKIN_CHECK(mTitleMedia = findChild("title_media"));
+ SKIN_CHECK(mTitleMediaText = findChild("media_info"));
+
+ // PBR
+ SKIN_CHECK(mMaterialCtrlPBR = findChild("pbr_control"));
+ SKIN_CHECK(mBaseTexturePBR = findChild("base_color_picker"));
+ SKIN_CHECK(mBaseTintPBR = findChild("base_color_tint_picker"));
+ SKIN_CHECK(mNormalTexturePBR = findChild("normal_map_picker"));
+ SKIN_CHECK(mORMTexturePBR = findChild("metallic_map_picker"));
+ SKIN_CHECK(mEmissiveTexturePBR = findChild("emissive_map_picker"));
+ SKIN_CHECK(mEmissiveTintPBR = findChild("emissive_color_tint_picker"));
+ SKIN_CHECK(mCheckDoubleSidedPBR = findChild("double sided"));
+ SKIN_CHECK(mAlphaPBR = findChild("transparency"));
+ SKIN_CHECK(mLabelAlphaModePBR = findChild("blend mode label"));
+ SKIN_CHECK(mAlphaModePBR = findChild("alpha mode"));
+ SKIN_CHECK(mMaskCutoffPBR = findChild("alpha cutoff"));
+ SKIN_CHECK(mMetallicFactorPBR = findChild("metalness factor"));
+ SKIN_CHECK(mRoughnessFactorPBR = findChild("roughness factor"));
+ SKIN_CHECK(mBtnSavePBR = findChild("save_selected_pbr"));
+
+ //
+ // hook up callbacks and do setup of all relevant UI elements here
+ //
+ mTabsPBRMatMedia->setCommitCallback(boost::bind(&FSPanelFace::onMatTabChange, this));
+ // common controls and parameters for Blinn-Phong and PBR
+ mBtnCopyFaces->setCommitCallback(boost::bind(&FSPanelFace::onCopyFaces, this));
+ mBtnPasteFaces->setCommitCallback(boost::bind(&FSPanelFace::onPasteFaces, this));
+ mCtrlGlow->setCommitCallback(boost::bind(&FSPanelFace::onCommitGlow, this));
+ mCtrlRpt->setCommitCallback(boost::bind(&FSPanelFace::onCommitRepeatsPerMeter, this));
+
+ // Blinn-Phong alpha parameters
+ mCtrlColorTransp->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlpha, this));
+ mComboAlphaMode->setCommitCallback(boost::bind(&FSPanelFace::onCommitAlphaMode, this));
+ mCtrlMaskCutoff->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialMaskCutoff, this));
+ mCheckFullbright->setCommitCallback(boost::bind(&FSPanelFace::onCommitFullbright, this));
+
+ // Blinn-Phong texture transforms and controls
+ mComboTexGen->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexGen, this));
+ mCheckPlanarAlign->setCommitCallback(boost::bind(&FSPanelFace::onCommitPlanarAlign, this));
+ mComboBumpiness->setCommitCallback(boost::bind(&FSPanelFace::onCommitBump, this));
+ mComboShininess->setCommitCallback(boost::bind(&FSPanelFace::onCommitShiny, this));
+ mCtrlTexScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureScaleX, this));
+ mCtrlTexScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureScaleY, this));
+ mCtrlTexOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureOffsetX, this));
+ mCtrlTexOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureOffsetY, this));
+ mCtrlTexRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitTextureRot, this));
+ mCtrlBumpyScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyScaleX, this));
+ mCtrlBumpyScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyScaleY, this));
+ mCtrlBumpyOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyOffsetX, this));
+ mCtrlBumpyOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyOffsetY, this));
+ mCtrlBumpyRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialBumpyRot, this));
+ mCtrlShinyScaleU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyScaleX, this));
+ mCtrlShinyScaleV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyScaleY, this));
+ mCtrlShinyOffsetU->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyOffsetX, this));
+ mCtrlShinyOffsetV->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyOffsetY, this));
+ mCtrlShinyRot->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialShinyRot, this));
+ mCtrlGlossiness->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialGloss, this));
+ mCtrlEnvironment->setCommitCallback(boost::bind(&FSPanelFace::onCommitMaterialEnv, this));
+
+ // Blinn-Phong Diffuse tint color swatch
+ mColorSwatch->setCommitCallback(boost::bind(&FSPanelFace::onCommitColor, this));
+ mColorSwatch->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelColor, this));
+ mColorSwatch->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectColor, this));
+
+ // Blinn-Phong Diffuse texture swatch
+ mTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE);
+ mTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitTexture, this, _1, _2));
+ mTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelTexture, this));
+ mTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2));
+ mTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2));
+ mTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+ mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
+
+ // Blinn-Phong Normal texture swatch
+ mBumpyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL);
+ mBumpyTextureCtrl->setBlankImageAssetID(BLANK_OBJECT_NORMAL);
+ mBumpyTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitNormalTexture, this, _1, _2));
+ mBumpyTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelNormalTexture, this));
+ mBumpyTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2));
+ mBumpyTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2));
+ mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+ mBumpyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
+
+ // Blinn-Phong Specular texture swatch
+ mShinyTextureCtrl->setDefaultImageAssetID(DEFAULT_OBJECT_SPECULAR);
+ mShinyTextureCtrl->setCommitCallback(boost::bind(&FSPanelFace::onCommitSpecularTexture, this, _1, _2));
+ mShinyTextureCtrl->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelSpecularTexture, this));
+ mShinyTextureCtrl->setDragCallback(boost::bind(&FSPanelFace::onDragTexture, this, _2));
+ mShinyTextureCtrl->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2));
+ mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+ mShinyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
+
+ // Blinn-Phong Specular tint color swatch
+ mShinyColorSwatch->setCommitCallback(boost::bind(&FSPanelFace::onCommitShinyColor, this));
+ mShinyColorSwatch->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelShinyColor, this));
+ mShinyColorSwatch->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectShinyColor, this));
+ mShinyColorSwatch->setCanApplyImmediately(TRUE);
+
+ // Texture alignment and maps synchronization
+ mBtnAlignMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickAutoFix, this));
+ mBtnAlignTextures->setCommitCallback(boost::bind(&FSPanelFace::onAlignTexture, this));
+ mCheckSyncMaterials->setCommitCallback(boost::bind(&FSPanelFace::onClickMapsSync, this));
+
+ // Media
+ mBtnDeleteMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnDeleteMedia, this));
+ mBtnAddMedia->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnAddMedia, this));
+
+ // PBR Base Material swatch
+ // mMaterialCtrlPBR->setDefaultImageAssetID(LLUUID::null); // we have no default material, and null is standard for LLUUID -Zi
+ mMaterialCtrlPBR->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID);
+ mMaterialCtrlPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this));
+ mMaterialCtrlPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this));
+ mMaterialCtrlPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this));
+ mMaterialCtrlPBR->setDragCallback(boost::bind(&FSPanelFace::onDragPbr, this, _2));
+ mMaterialCtrlPBR->setOnTextureSelectedCallback(boost::bind(&FSPanelFace::onPbrSelectionChanged, this, _1));
+ mMaterialCtrlPBR->setOnCloseCallback(boost::bind(&FSPanelFace::onCloseTexturePicker, this, _2));
+ mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_NONE);
+ mMaterialCtrlPBR->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ mMaterialCtrlPBR->setBakeTextureEnabled(false);
+ mMaterialCtrlPBR->setInventoryPickType(PICK_MATERIAL);
+
+ // PBR Base Color texture swatch
+ mBaseTexturePBR->setDefaultImageAssetID(DEFAULT_OBJECT_TEXTURE);
+ mBaseTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mBaseTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1));
+ mBaseTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1));
+
+ // PBR Base Color tint color swatch
+ mBaseTintPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mBaseTintPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1));
+ mBaseTintPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1));
+
+ // PBR Base Normal map swatch
+ mNormalTexturePBR->setDefaultImageAssetID(DEFAULT_OBJECT_NORMAL);
+ mNormalTexturePBR->setBlankImageAssetID(BLANK_OBJECT_NORMAL);
+ mNormalTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mNormalTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1));
+ mNormalTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1));
+
+ // PBR Base Emissive map swatch
+ mEmissiveTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mEmissiveTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1));
+ mEmissiveTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1));
+
+ // PBR Emissive tint color swatch
+ mEmissiveTintPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mEmissiveTintPBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1));
+ mEmissiveTintPBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1));
+
+ // PBR Base (O)RM map swatch
+ mORMTexturePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mORMTexturePBR->setOnCancelCallback(boost::bind(&FSPanelFace::onCancelPbr, this, _1));
+ mORMTexturePBR->setOnSelectCallback(boost::bind(&FSPanelFace::onSelectPbr, this, _1));
+
+ // PBR parameters
+ mCheckDoubleSidedPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mAlphaPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mAlphaModePBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mMaskCutoffPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mMetallicFactorPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+ mRoughnessFactorPBR->setCommitCallback(boost::bind(&FSPanelFace::onCommitPbr, this, _1));
+
+ // PBR Save material button
+ mBtnSavePBR->setCommitCallback(boost::bind(&FSPanelFace::onClickBtnSavePBR, this));
+
+ // Only allow fully permissive textures
+ if (!gAgent.isGodlike())
+ {
+ mBaseTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER);
+ mNormalTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER);
+ mORMTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER);
+ mEmissiveTexturePBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER);
+ }
+
+ //
+ // set up user interface
+ //
+
+ LLGLTFMaterialList::addSelectionUpdateCallback(onMaterialOverrideReceived);
+ sMaterialOverrideSelection.connect();
+
+ changePrecision(gSavedSettings.getS32("FSBuildToolDecimalPrecision"));
+
+ selectMaterialType(MATMEDIA_PBR); // TODO: add tab switching signal
+ selectMatChannel(MATTYPE_DIFFUSE); // TODO: add tab switching signal
+ selectPBRChannel(PBRTYPE_RENDER_MATERIAL_ID); // TODO: add tab switching signal
+
+ return TRUE;
+}
+
+//
+// Things the UI provides...
+//
+
+LLUUID FSPanelFace::getCurrentNormalMap() { return mBumpyTextureCtrl->getImageAssetID(); }
+LLUUID FSPanelFace::getCurrentSpecularMap() { return mShinyTextureCtrl->getImageAssetID(); }
+U32 FSPanelFace::getCurrentShininess() { return mComboShininess->getCurrentIndex(); }
+U32 FSPanelFace::getCurrentBumpiness() { return mComboBumpiness->getCurrentIndex(); }
+U8 FSPanelFace::getCurrentDiffuseAlphaMode() { return (U8)mComboAlphaMode->getCurrentIndex(); }
+U8 FSPanelFace::getCurrentAlphaMaskCutoff() { return (U8)mCtrlMaskCutoff->getValue().asInteger(); }
+U8 FSPanelFace::getCurrentEnvIntensity() { return (U8)mCtrlEnvironment->getValue().asInteger(); }
+U8 FSPanelFace::getCurrentGlossiness() { return (U8)mCtrlGlossiness->getValue().asInteger(); }
+F32 FSPanelFace::getCurrentBumpyRot() { return mCtrlBumpyRot->getValue().asReal(); }
+F32 FSPanelFace::getCurrentBumpyScaleU() { return mCtrlBumpyScaleU->getValue().asReal(); }
+F32 FSPanelFace::getCurrentBumpyScaleV() { return mCtrlBumpyScaleV->getValue().asReal(); }
+F32 FSPanelFace::getCurrentBumpyOffsetU() { return mCtrlBumpyOffsetU->getValue().asReal(); }
+F32 FSPanelFace::getCurrentBumpyOffsetV() { return mCtrlBumpyOffsetV->getValue().asReal(); }
+F32 FSPanelFace::getCurrentShinyRot() { return mCtrlShinyRot->getValue().asReal(); }
+F32 FSPanelFace::getCurrentShinyScaleU() { return mCtrlShinyScaleU->getValue().asReal(); }
+F32 FSPanelFace::getCurrentShinyScaleV() { return mCtrlShinyScaleV->getValue().asReal(); }
+F32 FSPanelFace::getCurrentShinyOffsetU() { return mCtrlShinyOffsetU->getValue().asReal(); }
+F32 FSPanelFace::getCurrentShinyOffsetV() { return mCtrlShinyOffsetV->getValue().asReal(); }
+
+// UI provided diffuse parameters
+F32 FSPanelFace::getCurrentTextureRot() { return mCtrlTexRot->getValue().asReal(); }
+F32 FSPanelFace::getCurrentTextureScaleU() { return mCtrlTexScaleU->getValue().asReal(); }
+F32 FSPanelFace::getCurrentTextureScaleV() { return mCtrlTexScaleV->getValue().asReal(); }
+F32 FSPanelFace::getCurrentTextureOffsetU() { return mCtrlTexOffsetU->getValue().asReal(); }
+F32 FSPanelFace::getCurrentTextureOffsetV() { return mCtrlTexOffsetV->getValue().asReal(); }
+//
+
+LLRender::eTexIndex FSPanelFace::getTextureChannelToEdit()
+{
+ LLRender::eTexIndex channel_to_edit = LLRender::DIFFUSE_MAP;
+
+ S32 matmedia_selection = getCurrentMaterialType();
+
+ if (matmedia_selection == MATMEDIA_MATERIAL)
+ {
+ channel_to_edit = (LLRender::eTexIndex) getCurrentMatChannel();
+
+ if (channel_to_edit == LLRender::NORMAL_MAP && getCurrentNormalMap().isNull()) return LLRender::DIFFUSE_MAP;
+ if (channel_to_edit == LLRender::SPECULAR_MAP && getCurrentSpecularMap().isNull()) return LLRender::DIFFUSE_MAP;
+ }
+
+ // this is technically not correct, the return type is not the same, which forces us to cast -Zi
+ else if (matmedia_selection == MATMEDIA_PBR)
+ {
+ channel_to_edit = (LLRender::eTexIndex) getCurrentPBRChannel();
+
+ if (channel_to_edit == PBRTYPE_NORMAL && mNormalTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR;
+ if (channel_to_edit == PBRTYPE_METALLIC_ROUGHNESS && mORMTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR;
+ if (channel_to_edit == PBRTYPE_EMISSIVE && mEmissiveTexturePBR->getImageAssetID().isNull()) return (LLRender::eTexIndex) PBRTYPE_BASE_COLOR;
+ }
+
+ return channel_to_edit;
+}
+
+LLRender::eTexIndex FSPanelFace::getTextureDropChannel()
+{
+ if (getCurrentMaterialType() == MATMEDIA_MATERIAL)
+ {
+ return getTextureChannelToEdit();
+ }
+
+ return LLRender::eTexIndex(MATTYPE_DIFFUSE);
+}
+
+LLGLTFMaterial::TextureInfo FSPanelFace::getPBRDropChannel()
+{
+ if (getCurrentMaterialType() == MATMEDIA_PBR)
+ {
+ S32 current_pbr_channel = getCurrentPBRChannel();
+ if (current_pbr_channel == PBRTYPE_NORMAL) return LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL;
+ if (current_pbr_channel == PBRTYPE_METALLIC_ROUGHNESS) return LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS;
+ if (current_pbr_channel == PBRTYPE_EMISSIVE) return LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE;
+ }
+ return LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR;
+}
+
+LLMaterialPtr FSPanelFace::createDefaultMaterial(LLMaterialPtr current_material)
+{
+ LLMaterialPtr new_material(current_material.notNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
+ llassert_always(new_material);
+
+ // Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture
+ //
+ new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode());
+ return new_material;
+}
+
+void FSPanelFace::onVisibilityChange(BOOL new_visibility)
+{
+ if (new_visibility)
+ {
+ gAgent.showLatestFeatureNotification("gltf");
+ }
+ LLPanel::onVisibilityChange(new_visibility);
+}
+
+void FSPanelFace::draw()
+{
+ // TODO(Beq) why does it have to call applyTE?
+ updateCopyTexButton();
+
+ // grab media name/title and update the UI widget
+ // Todo: move it, it's preferable not to update
+ // labels inside draw
+ updateMediaTitle();
+
+ LLPanel::draw();
+
+ // not sure if there isn't a better place for this, but for the time being this seems to work,
+ // and trying other places always failed in some way or other -Zi
+ static U64MicrosecondsImplicit next_update_time = 0LL;
+ if (mUnsavedChanges && gFrameTime > next_update_time)
+ {
+ LL_DEBUGS("APPLY_GLTF_CHANGES") << "detected unsaved changes: " << mUnsavedChanges << LL_ENDL;
+
+ LLPointer mat = new LLGLTFMaterial();
+ getGLTFMaterial(mat);
+
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+ LLRenderMaterialOverrideFunctor override_func(mat, mUnsavedChanges);
+ selected_objects->applyToNodes(&override_func);
+
+ LLGLTFMaterialList::flushUpdates();
+
+ mUnsavedChanges = 0;
+
+ next_update_time = gFrameTime + 100000LL; // 100 ms
+
+ // delete mat; // do not delete mat, it's still referenced elsewhere (probably in the material list) -Zi
+ }
+
+ if (sMaterialOverrideSelection.update())
+ {
+ setMaterialOverridesFromSelection();
+ updatePBROverrideDisplay();
+ }
+}
+
+void FSPanelFace::sendTexture()
+{
+ if (!mTextureCtrl->getTentative())
+ {
+ // we grab the item id first, because we want to do a
+ // permissions check in the selection manager. ARGH!
+ LLUUID id = mTextureCtrl->getImageItemID();
+ if (id.isNull())
+ {
+ id = mTextureCtrl->getImageAssetID();
+ }
+ if (!LLSelectMgr::getInstance()->selectionSetImage(id, getCurrentMaterialType()==MATMEDIA_PBR) )
+ {
+ // need to refresh value in texture ctrl
+ refresh();
+ }
+ }
+}
+
+void FSPanelFace::sendBump(U32 bumpiness)
+{
+ if (bumpiness < BUMPY_TEXTURE)
+ {
+ LL_DEBUGS("Materials") << "clearing bumptexture control" << LL_ENDL;
+ mBumpyTextureCtrl->clear();
+ mBumpyTextureCtrl->setImageAssetID(LLUUID());
+ }
+
+ updateBumpyControls(bumpiness == BUMPY_TEXTURE, true);
+
+ LLUUID current_normal_map = mBumpyTextureCtrl->getImageAssetID();
+
+ U8 bump = (U8)bumpiness & TEM_BUMP_MASK;
+
+ // Clear legacy bump to None when using an actual normal map
+ //
+ if (!current_normal_map.isNull())
+ {
+ bump = 0;
+ }
+
+ // Set the normal map or reset it to null as appropriate
+ //
+ LLSelectedTEMaterial::setNormalID(this, current_normal_map);
+ LLSelectMgr::getInstance()->selectionSetBumpmap(bump, mBumpyTextureCtrl->getImageItemID());
+}
+
+void FSPanelFace::sendTexGen()
+{
+ U8 tex_gen = (U8) mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT;
+ LLSelectMgr::getInstance()->selectionSetTexGen(tex_gen);
+}
+
+void FSPanelFace::sendShiny(U32 shininess)
+{
+ if (shininess < SHINY_TEXTURE)
+ {
+ mShinyTextureCtrl->clear();
+ mShinyTextureCtrl->setImageAssetID(LLUUID());
+ }
+
+ LLUUID specmap = getCurrentSpecularMap();
+
+ U8 shiny = (U8)shininess & TEM_SHINY_MASK;
+ if (!specmap.isNull())
+ {
+ shiny = 0;
+ }
+
+ LLSelectedTEMaterial::setSpecularID(this, specmap);
+ LLSelectMgr::getInstance()->selectionSetShiny(shiny, mShinyTextureCtrl->getImageItemID());
+
+ updateShinyControls(!specmap.isNull(), true);
+}
+
+void FSPanelFace::sendFullbright()
+{
+ U8 fullbright = mCheckFullbright->get() ? TEM_FULLBRIGHT_MASK : 0;
+ LLSelectMgr::getInstance()->selectionSetFullbright(fullbright);
+}
+
+void FSPanelFace::sendColor()
+{
+ LLSelectMgr::getInstance()->selectionSetColorOnly(mColorSwatch->get());
+}
+
+void FSPanelFace::sendAlpha()
+{
+ F32 alpha = (100.0f - mCtrlColorTransp->get()) / 100.0f;
+ LLSelectMgr::getInstance()->selectionSetAlphaOnly(alpha);
+}
+
+void FSPanelFace::sendGlow()
+{
+ LLSelectMgr::getInstance()->selectionSetGlow(mCtrlGlow->get());
+}
+
+struct FSPanelFaceSetTEFunctor : public LLSelectedTEFunctor
+{
+ FSPanelFaceSetTEFunctor(FSPanelFace* panel) :
+ mPanel(panel)
+ {
+ }
+
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ BOOL valid;
+ F32 value;
+ std::string prefix;
+
+ // Effectively the same as MATMEDIA_PBR - separate for the sake of clarity
+
+ const std::string& tab_name = mPanel->mTabsMatChannel->getCurrentPanel()->getName();
+
+ prefix = "Tex";
+ if (tab_name == "panel_blinn_phong_normal")
+ {
+ prefix = "bumpy";
+ }
+ else if (tab_name == "panel_blinn_phong_specular")
+ {
+ prefix = "shiny";
+ }
+
+ LLSpinCtrl* ctrlTexScaleS = mPanel->findChild(prefix + "ScaleU");
+ LLSpinCtrl* ctrlTexScaleT = mPanel->findChild(prefix + "ScaleV");
+ LLSpinCtrl* ctrlTexOffsetS = mPanel->findChild(prefix + "OffsetU");
+ LLSpinCtrl* ctrlTexOffsetT = mPanel->findChild(prefix + "OffsetV");
+ LLSpinCtrl* ctrlTexRotation = mPanel->findChild(prefix + "Rot");
+
+ bool align_planar = mPanel->mCheckPlanarAlign->get();
+
+ llassert(comboTexGen);
+ llassert(object);
+
+ if (ctrlTexScaleS)
+ {
+ valid = !ctrlTexScaleS->getTentative();
+ if (valid || align_planar)
+ {
+ value = ctrlTexScaleS->get();
+ if (mPanel->mComboTexGen->getCurrentIndex() == 1)
+ {
+ value *= 0.5f;
+ }
+ object->setTEScaleS(te, value);
+
+ if (align_planar)
+ {
+ FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, value, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, value, te, object->getID());
+ }
+ }
+ }
+
+ if (ctrlTexScaleT)
+ {
+ valid = !ctrlTexScaleT->getTentative();
+ if (valid || align_planar)
+ {
+ value = ctrlTexScaleT->get();
+ if (mPanel->mComboTexGen->getCurrentIndex() == 1)
+ {
+ value *= 0.5f;
+ }
+ object->setTEScaleT(te, value);
+
+ if (align_planar)
+ {
+ FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, value, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, value, te, object->getID());
+ }
+ }
+ }
+
+ if (ctrlTexOffsetS)
+ {
+ valid = !ctrlTexOffsetS->getTentative();
+ if (valid || align_planar)
+ {
+ value = ctrlTexOffsetS->get();
+ object->setTEOffsetS(te, value);
+
+ if (align_planar)
+ {
+ FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, value, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, value, te, object->getID());
+ }
+ }
+ }
+
+ if (ctrlTexOffsetT)
+ {
+ valid = !ctrlTexOffsetT->getTentative();
+ if (valid || align_planar)
+ {
+ value = ctrlTexOffsetT->get();
+ object->setTEOffsetT(te, value);
+
+ if (align_planar)
+ {
+ FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, value, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, value, te, object->getID());
+ }
+ }
+ }
+
+ if (ctrlTexRotation)
+ {
+ valid = !ctrlTexRotation->getTentative();
+ if (valid || align_planar)
+ {
+ value = ctrlTexRotation->get() * DEG_TO_RAD;
+ object->setTERotation(te, value);
+
+ if (align_planar)
+ {
+ FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, value, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, value, te, object->getID());
+ }
+ }
+ }
+ return true;
+ }
+private:
+ FSPanelFace* mPanel;
+};
+
+// Functor that aligns a face to mCenterFace
+struct FSPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor
+{
+ FSPanelFaceSetAlignedTEFunctor(FSPanelFace* panel, LLFace* center_face) :
+ mPanel(panel),
+ mCenterFace(center_face)
+ {
+ }
+
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ LLFace* facep = object->mDrawable->getFace(te);
+ if (!facep)
+ {
+ return true;
+ }
+
+ if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te)
+ {
+ return true;
+ }
+
+ bool set_aligned = true;
+ if (facep == mCenterFace)
+ {
+ set_aligned = false;
+ }
+ if (set_aligned)
+ {
+ LLVector2 uv_offset, uv_scale;
+ F32 uv_rot;
+ set_aligned = facep->calcAlignedPlanarTE(mCenterFace, &uv_offset, &uv_scale, &uv_rot);
+ if (set_aligned)
+ {
+ object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]);
+ object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]);
+ object->setTERotation(te, uv_rot);
+
+ FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID());
+
+ FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
+
+ FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
+ }
+ }
+ if (!set_aligned)
+ {
+ FSPanelFaceSetTEFunctor setfunc(mPanel);
+ setfunc.apply(object, te);
+ }
+ return true;
+ }
+private:
+ FSPanelFace* mPanel;
+ LLFace* mCenterFace;
+};
+
+struct FSPanelFaceSetAlignedConcreteTEFunctor : public LLSelectedTEFunctor
+{
+ FSPanelFaceSetAlignedConcreteTEFunctor(FSPanelFace* panel, LLFace* center_face, LLRender::eTexIndex map) :
+ mPanel(panel),
+ mChefFace(center_face),
+ mMap(map)
+ {
+ }
+
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ LLFace* facep = object->mDrawable->getFace(te);
+ if (!facep)
+ {
+ return true;
+ }
+
+ if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te)
+ {
+ return true;
+ }
+
+ if (mChefFace != facep)
+ {
+ LLVector2 uv_offset, uv_scale;
+ F32 uv_rot;
+ if (facep->calcAlignedPlanarTE(mChefFace, &uv_offset, &uv_scale, &uv_rot, mMap))
+ {
+ switch (mMap)
+ {
+ case LLRender::DIFFUSE_MAP:
+ object->setTEOffset(te, uv_offset.mV[VX], uv_offset.mV[VY]);
+ object->setTEScale(te, uv_scale.mV[VX], uv_scale.mV[VY]);
+ object->setTERotation(te, uv_rot);
+ break;
+
+ case LLRender::NORMAL_MAP:
+ FSPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
+ break;
+
+ case LLRender::SPECULAR_MAP:
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
+ FSPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
+ break;
+
+ default: /*make compiler happy*/
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ FSPanelFace* mPanel;
+ LLFace* mChefFace;
+ LLRender::eTexIndex mMap;
+};
+
+// Functor that tests if a face is aligned to mCenterFace
+struct FSPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor
+{
+ FSPanelFaceGetIsAlignedTEFunctor(LLFace* center_face) :
+ mCenterFace(center_face)
+ {
+ }
+
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ LLFace* facep = object->mDrawable->getFace(te);
+ if (!facep)
+ {
+ return false;
+ }
+
+ if (facep->getViewerObject()->getVolume()->getNumVolumeFaces() <= te)
+ { //volume face does not exist, can't be aligned
+ return false;
+ }
+
+ if (facep == mCenterFace)
+ {
+ return true;
+ }
+
+ LLVector2 aligned_st_offset, aligned_st_scale;
+ F32 aligned_st_rot;
+ if ( facep->calcAlignedPlanarTE(mCenterFace, &aligned_st_offset, &aligned_st_scale, &aligned_st_rot) )
+ {
+ const LLTextureEntry* tep = facep->getTextureEntry();
+ LLVector2 st_offset, st_scale;
+ tep->getOffset(&st_offset.mV[VX], &st_offset.mV[VY]);
+ tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]);
+ F32 st_rot = tep->getRotation();
+
+ bool eq_offset_x = is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12);
+ bool eq_offset_y = is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12);
+ bool eq_scale_x = is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12);
+ bool eq_scale_y = is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12);
+ bool eq_rot = is_approx_equal_fraction(st_rot, aligned_st_rot, 6);
+
+ // needs a fuzzy comparison, because of fp errors
+ if (eq_offset_x &&
+ eq_offset_y &&
+ eq_scale_x &&
+ eq_scale_y &&
+ eq_rot)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ private:
+ LLFace* mCenterFace;
+};
+
+struct FSPanelFaceSendFunctor : public LLSelectedObjectFunctor
+{
+ virtual bool apply(LLViewerObject* object)
+ {
+ object->sendTEUpdate();
+ return true;
+ }
+};
+
+void FSPanelFace::sendTextureInfo()
+{
+ if (mCheckPlanarAlign->getValue().asBoolean())
+ {
+ LLFace* last_face = NULL;
+ bool identical_face =false;
+ LLSelectedTE::getFace(last_face, identical_face);
+ FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+ }
+ else
+ {
+ FSPanelFaceSetTEFunctor setfunc(this);
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+ }
+
+ FSPanelFaceSendFunctor sendfunc;
+ LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc);
+}
+
+void FSPanelFace::alignTextureLayer()
+{
+ LLFace* last_face = NULL;
+ bool identical_face = false;
+ LLSelectedTE::getFace(last_face, identical_face);
+
+ // TODO: make this respect PBR channels -Zi
+ FSPanelFaceSetAlignedConcreteTEFunctor setfunc(this, last_face, getTextureChannelToEdit());
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+}
+
+void FSPanelFace::getState()
+{
+ updateUI();
+}
+
+void FSPanelFace::updateUI(bool force_set_values /*false*/)
+{ //set state of UI to match state of texture entry(ies) (calls setEnabled, setValue, etc, but NOT setVisible)
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ LLViewerObject* objectp = node ? node->getObject() : NULL;
+
+ if (objectp
+ && objectp->getPCode() == LL_PCODE_VOLUME
+ && objectp->permModify())
+ {
+ // TODO: Find out what "permanent" objects are supposed to allow to be edited. Right now this will
+ // completely blank out the texture panel, so we could just move that into the if() above -Zi
+ bool editable = !objectp->isPermanentEnforced();
+ bool attachment = objectp->isAttachment();
+
+ // this object's faces can potentially be edited by us, so display the edit controls unless this is
+ // a "permanent" pathfinding(?) object -Zi
+ gSavedSettings.setBOOL("FSInternalCanEditObjectFaces", editable);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "show face edit controls: " << editable << LL_ENDL;
+
+ // TODO: editable always true here so we don't have to go through all the following code and strip it out
+ // until we know what the permanent thing abobe is supposed to do and we know if blanking out all
+ // controls has any unforseen side effects to editing. -Zi
+ editable = true;
+
+ bool has_pbr_material;
+ bool has_faces_without_pbr;
+ updateUIGLTF(objectp, has_pbr_material, has_faces_without_pbr, force_set_values);
+
+ // TODO: if has_pbr_material AND has_faces_without_pbr give "Mixed Selection!" warning somehow
+
+ mTabsPBRMatMedia->enableTabButton(
+ mTabsPBRMatMedia->getIndexForPanel(
+ mTabsPBRMatMedia->getPanelByName("panel_material_type_blinn_phong")), editable );
+
+ // only turn on auto-adjust button if there is a media renderer and the media is loaded
+ mBtnAlignMedia->setEnabled(editable);
+
+ bool enable_material_controls = (!gSavedSettings.getBOOL("SyncMaterialSettings"));
+
+ // *NOTE: The "identical" variable is currently only used to decide if
+ // the texgen control should be tentative - this is not used by GLTF
+ // materials. -Cosmic;2022-11-09
+ bool identical = true; // true because it is anded below
+ bool identical_diffuse = false;
+ bool identical_norm = false;
+ bool identical_spec = false;
+
+ LLUUID id;
+ LLUUID normmap_id;
+ LLUUID specmap_id;
+
+ LLSelectedTE::getTexId(id, identical_diffuse);
+ LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm);
+ LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec);
+
+ mTabsMatChannel->setEnabled(editable);
+ mTabsPBRChannel->setEnabled(editable);
+
+ mCheckSyncMaterials->setEnabled(editable);
+ mCheckSyncMaterials->setValue(gSavedSettings.getBOOL("SyncMaterialSettings"));
+
+ updateVisibility(objectp);
+
+ LLColor4 color = LLColor4::white;
+ bool identical_color = false;
+
+ LLSelectedTE::getColor(color, identical_color);
+ LLColor4 prev_color = mColorSwatch->get();
+
+ mColorSwatch->setOriginal(color);
+ mColorSwatch->set(color, force_set_values || (prev_color != color) || !editable);
+
+ mColorSwatch->setValid(editable);
+ mColorSwatch->setEnabled(editable);
+ mColorSwatch->setCanApplyImmediately( editable );
+
+ F32 transparency = (1.f - color.mV[VALPHA]) * 100.f;
+ mCtrlColorTransp->setValue(editable ? transparency : 0);
+ mCtrlColorTransp->setEnabled(editable );
+ mColorTransPercent->setMouseOpaque(editable );
+
+ U8 shiny = 0;
+ // Shiny
+ {
+ bool identical_shiny = false;
+
+ // Shiny - Legacy only, Blinn-Pbong specular is done further down
+ LLSelectedTE::getShiny(shiny, identical_shiny);
+ identical = identical && identical_shiny;
+
+ shiny = specmap_id.isNull() ? shiny : SHINY_TEXTURE;
+
+ mComboShininess->selectNthItem(shiny);
+ mComboShininess->setEnabled(editable);
+ mComboShininess->setTentative(!identical_shiny);
+ mLabelShininess->setEnabled(editable);
+ }
+
+ U8 bumpy = 0;
+ // Bumpy
+ {
+ bool identical_bumpy = false;
+ LLSelectedTE::getBumpmap(bumpy, identical_bumpy);
+
+ LLUUID norm_map_id = getCurrentNormalMap();
+
+ bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
+
+ mComboBumpiness->selectNthItem(bumpy);
+ mComboBumpiness->setEnabled(editable);
+ mComboBumpiness->setTentative(!identical_bumpy);
+ mLabelBumpiness->setEnabled(editable);
+ }
+
+ // Texture
+ {
+ mIsAlpha = false;
+
+ LLGLenum image_format = GL_RGB;
+ bool identical_image_format = false;
+ LLSelectedTE::getImageFormat(image_format, identical_image_format);
+
+ switch (image_format)
+ {
+ case GL_RGBA:
+ case GL_ALPHA:
+ {
+ mIsAlpha = true;
+ }
+ break;
+
+ case GL_RGB: break;
+ default:
+ {
+ LL_WARNS() << "Unexpected tex format in FSPanelFace...resorting to no alpha" << LL_ENDL;
+ }
+ break;
+ }
+
+ if (LLViewerMedia::getInstance()->textureHasMedia(id))
+ {
+ mBtnAlignMedia->setEnabled(editable);
+ }
+
+ if (identical_diffuse)
+ {
+ mTextureCtrl->setTentative(false);
+ mTextureCtrl->setEnabled(editable);
+ mTextureCtrl->setImageAssetID(id);
+ mComboAlphaMode->setEnabled(editable && mIsAlpha && transparency <= 0.f );
+ mCtrlMaskCutoff->setEnabled(editable && mIsAlpha );
+
+ mTextureCtrl->setBakeTextureEnabled(true);
+ }
+ else if (id.isNull())
+ {
+ // None selected
+ mTextureCtrl->setTentative(false);
+ mTextureCtrl->setEnabled(false);
+ mTextureCtrl->setImageAssetID(LLUUID::null);
+ mComboAlphaMode->setEnabled(false);
+ mCtrlMaskCutoff->setEnabled(false);
+
+ mTextureCtrl->setBakeTextureEnabled(false);
+ }
+ else
+ {
+ // Tentative: multiple selected with different textures
+ mTextureCtrl->setTentative(true);
+ mTextureCtrl->setEnabled(editable );
+ mTextureCtrl->setImageAssetID(id);
+ mComboAlphaMode->setEnabled(editable && mIsAlpha && transparency <= 0.f );
+ mCtrlMaskCutoff->setEnabled(editable && mIsAlpha );
+
+ mTextureCtrl->setBakeTextureEnabled(true);
+ }
+
+ mShinyTextureCtrl->setTentative(!identical_spec);
+ mShinyTextureCtrl->setEnabled(editable);
+ mShinyTextureCtrl->setImageAssetID(specmap_id);
+
+ mBumpyTextureCtrl->setTentative(!identical_norm);
+ mBumpyTextureCtrl->setEnabled(editable );
+ mBumpyTextureCtrl->setImageAssetID(normmap_id);
+
+ if (attachment)
+ {
+ // attachments are in world and in inventory,
+ // server doesn't support changing permissions
+ // in such case
+ mTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ mShinyTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+ }
+ else
+ {
+ mTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+ mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+ mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+ }
+
+ // 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->selectNthItem(alpha_mode);
+
+ updateAlphaControls();
+
+ mLabelAlphaMode->setEnabled(mComboAlphaMode->getEnabled());
+ }
+
+ // planar align
+ bool align_planar = mCheckPlanarAlign->get();
+ bool identical_planar_aligned = false;
+ {
+ const bool texture_info_selected = (getCurrentMaterialType() == MATMEDIA_PBR && getCurrentPBRChannel() != PBRTYPE_RENDER_MATERIAL_ID);
+ const bool enabled = (editable && isIdenticalPlanarTexgen() && !texture_info_selected);
+
+ mCheckPlanarAlign->setValue(align_planar && enabled);
+ mCheckPlanarAlign->setEnabled(enabled);
+ mBtnAlignTextures->setEnabled(enabled && LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1);
+
+ if (align_planar && enabled)
+ {
+ LLFace* last_face = nullptr;
+ bool identical_face = false;
+ LLSelectedTE::getFace(last_face, identical_face);
+
+ FSPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face);
+ // this will determine if the texture param controls are tentative:
+ identical_planar_aligned = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&get_is_aligend_func);
+ }
+ }
+
+ // Needs to be public and before tex scale settings below to properly reflect
+ // behavior when in planar vs default texgen modes in the
+ // NORSPEC-84 et al
+ //
+ LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT;
+ bool identical_texgen = true;
+ bool identical_planar_texgen = false;
+
+ {
+ LLSelectedTE::getTexGen(selected_texgen, identical_texgen);
+ identical_planar_texgen = (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR));
+ }
+
+ // Texture scale
+ {
+ bool identical_diff_scale_s = false;
+ bool identical_spec_scale_s = false;
+ bool identical_norm_scale_s = false;
+
+ identical = align_planar ? identical_planar_aligned : identical;
+
+ F32 diff_scale_s = 1.f;
+ F32 spec_scale_s = 1.f;
+ F32 norm_scale_s = 1.f;
+
+ LLSelectedTE::getScaleS(diff_scale_s, identical_diff_scale_s);
+ LLSelectedTEMaterial::getSpecularRepeatX(spec_scale_s, identical_spec_scale_s);
+ LLSelectedTEMaterial::getNormalRepeatX(norm_scale_s, identical_norm_scale_s);
+
+ diff_scale_s = editable ? diff_scale_s : 1.0f;
+ diff_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
+
+ norm_scale_s = editable ? norm_scale_s : 1.0f;
+ norm_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
+
+ spec_scale_s = editable ? spec_scale_s : 1.0f;
+ spec_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
+
+ mCtrlTexScaleU->setValue(diff_scale_s);
+ mCtrlShinyScaleU->setValue(spec_scale_s);
+ mCtrlBumpyScaleU->setValue(norm_scale_s);
+
+ // TODO: do we need to enable/disable all these manually anymore? -Zi
+ /*
+ mCtrlTexScaleU->setEnabled(editable && has_material);
+
+ mCtrlShinyScaleU->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls);
+ mCtrlBumpyScaleU->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls);
+ childSetEnabled("flipTextureScaleSU", mCtrlShinyScaleU->getEnabled());
+ childSetEnabled("flipTextureScaleNU", mCtrlBumpyScaleU->getEnabled());
+ */
+
+ bool diff_scale_tentative = !(identical && identical_diff_scale_s);
+ bool norm_scale_tentative = !(identical && identical_norm_scale_s);
+ bool spec_scale_tentative = !(identical && identical_spec_scale_s);
+
+ mCtrlTexScaleU->setTentative( LLSD(diff_scale_tentative));
+ mCtrlShinyScaleU->setTentative(LLSD(spec_scale_tentative));
+ mCtrlBumpyScaleU->setTentative(LLSD(norm_scale_tentative));
+
+ mCheckSyncMaterials->setEnabled(editable && (specmap_id.notNull() || normmap_id.notNull()) && !align_planar);
+ }
+
+ {
+ bool identical_diff_scale_t = false;
+ bool identical_spec_scale_t = false;
+ bool identical_norm_scale_t = false;
+
+ F32 diff_scale_t = 1.f;
+ F32 spec_scale_t = 1.f;
+ F32 norm_scale_t = 1.f;
+
+ LLSelectedTE::getScaleT(diff_scale_t, identical_diff_scale_t);
+ LLSelectedTEMaterial::getSpecularRepeatY(spec_scale_t, identical_spec_scale_t);
+ LLSelectedTEMaterial::getNormalRepeatY(norm_scale_t, identical_norm_scale_t);
+
+ diff_scale_t = editable ? diff_scale_t : 1.0f;
+ diff_scale_t *= identical_planar_texgen ? 2.0f : 1.0f;
+
+ norm_scale_t = editable ? norm_scale_t : 1.0f;
+ norm_scale_t *= identical_planar_texgen ? 2.0f : 1.0f;
+
+ spec_scale_t = editable ? spec_scale_t : 1.0f;
+ spec_scale_t *= identical_planar_texgen ? 2.0f : 1.0f;
+
+ bool diff_scale_tentative = !identical_diff_scale_t;
+ bool norm_scale_tentative = !identical_norm_scale_t;
+ bool spec_scale_tentative = !identical_spec_scale_t;
+
+ // TODO: do we need to enable/disable all these manually anymore? -Zi
+ /*
+ mCtrlTexScaleV->setEnabled(editable && has_material);
+
+ mCtrlShinyScaleV->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls);
+ mCtrlBumpyScaleV->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls);
+ childSetEnabled("flipTextureScaleSV", mCtrlShinyScaleU->getEnabled());
+ childSetEnabled("flipTextureScaleNV", mCtrlBumpyScaleU->getEnabled());
+ */
+
+ if (force_set_values)
+ {
+ mCtrlTexScaleV->forceSetValue(diff_scale_t);
+ }
+ else
+ {
+ mCtrlTexScaleV->setValue(diff_scale_t);
+ }
+ mCtrlShinyScaleV->setValue(norm_scale_t);
+ mCtrlBumpyScaleV->setValue(spec_scale_t);
+
+ mCtrlTexScaleV->setTentative(LLSD(diff_scale_tentative));
+ mCtrlShinyScaleV->setTentative(LLSD(norm_scale_tentative));
+ mCtrlBumpyScaleV->setTentative(LLSD(spec_scale_tentative));
+ }
+
+ // Texture offset
+ {
+ bool identical_diff_offset_s = false;
+ bool identical_norm_offset_s = false;
+ bool identical_spec_offset_s = false;
+
+ F32 diff_offset_s = 0.0f;
+ F32 norm_offset_s = 0.0f;
+ F32 spec_offset_s = 0.0f;
+
+ LLSelectedTE::getOffsetS(diff_offset_s, identical_diff_offset_s);
+ LLSelectedTEMaterial::getNormalOffsetX(norm_offset_s, identical_norm_offset_s);
+ LLSelectedTEMaterial::getSpecularOffsetX(spec_offset_s, identical_spec_offset_s);
+
+ bool diff_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_s);
+ bool norm_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_s);
+ bool spec_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_s);
+
+ mCtrlTexOffsetU->setValue( editable ? diff_offset_s : 0.0f);
+ mCtrlBumpyOffsetU->setValue(editable ? norm_offset_s : 0.0f);
+ mCtrlShinyOffsetU->setValue(editable ? spec_offset_s : 0.0f);
+
+ mCtrlTexOffsetU->setTentative(LLSD(diff_offset_u_tentative));
+ mCtrlBumpyOffsetU->setTentative(LLSD(norm_offset_u_tentative));
+ mCtrlShinyOffsetU->setTentative(LLSD(spec_offset_u_tentative));
+
+ // TODO: do we need to enable/disable all these manually anymore? -Zi
+ /*
+ mCtrlTexOffsetU->setEnabled(editable && has_material);
+
+ mCtrlShinyOffsetU->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls);
+ mCtrlBumpyOffsetU->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls);
+ */
+ }
+
+ {
+ bool identical_diff_offset_t = false;
+ bool identical_norm_offset_t = false;
+ bool identical_spec_offset_t = false;
+
+ F32 diff_offset_t = 0.0f;
+ F32 norm_offset_t = 0.0f;
+ F32 spec_offset_t = 0.0f;
+
+ LLSelectedTE::getOffsetT(diff_offset_t, identical_diff_offset_t);
+ LLSelectedTEMaterial::getNormalOffsetY(norm_offset_t, identical_norm_offset_t);
+ LLSelectedTEMaterial::getSpecularOffsetY(spec_offset_t, identical_spec_offset_t);
+
+ bool diff_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_t);
+ bool norm_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_t);
+ bool spec_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_t);
+
+ mCtrlTexOffsetV->setValue( editable ? diff_offset_t : 0.0f);
+ mCtrlBumpyOffsetV->setValue(editable ? norm_offset_t : 0.0f);
+ mCtrlShinyOffsetV->setValue(editable ? spec_offset_t : 0.0f);
+
+ mCtrlTexOffsetV->setTentative(LLSD(diff_offset_v_tentative));
+ mCtrlBumpyOffsetV->setTentative(LLSD(norm_offset_v_tentative));
+ mCtrlShinyOffsetV->setTentative(LLSD(spec_offset_v_tentative));
+
+ // TODO: do we need to enable/disable all these manually anymore? -Zi
+ /*
+ mCtrlTexOffsetV->setEnabled(editable && has_material);
+
+ mCtrlShinyOffsetV->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls);
+ mCtrlBumpyOffsetV->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls);
+ */
+ }
+
+ // Texture rotation
+ {
+ bool identical_diff_rotation = false;
+ bool identical_norm_rotation = false;
+ bool identical_spec_rotation = false;
+
+ F32 diff_rotation = 0.f;
+ F32 norm_rotation = 0.f;
+ F32 spec_rotation = 0.f;
+
+ LLSelectedTE::getRotation(diff_rotation,identical_diff_rotation);
+ LLSelectedTEMaterial::getSpecularRotation(spec_rotation,identical_spec_rotation);
+ LLSelectedTEMaterial::getNormalRotation(norm_rotation,identical_norm_rotation);
+
+ bool diff_rot_tentative = !(align_planar ? identical_planar_aligned : identical_diff_rotation);
+ bool norm_rot_tentative = !(align_planar ? identical_planar_aligned : identical_norm_rotation);
+ bool spec_rot_tentative = !(align_planar ? identical_planar_aligned : identical_spec_rotation);
+
+ F32 diff_rot_deg = diff_rotation * RAD_TO_DEG;
+ F32 norm_rot_deg = norm_rotation * RAD_TO_DEG;
+ F32 spec_rot_deg = spec_rotation * RAD_TO_DEG;
+
+ // TODO: do we need to enable/disable all these manually anymore? -Zi
+ /*
+ mCtrlTexRot->setEnabled(editable && has_material);
+
+ mCtrlShinyRot->setEnabled(editable && has_material && specmap_id.notNull() && enable_material_controls);
+ mCtrlBumpyRot->setEnabled(editable && has_material && normmap_id.notNull() && enable_material_controls);
+ */
+
+ mCtrlTexRot->setTentative(diff_rot_tentative);
+ mCtrlBumpyRot->setTentative(LLSD(norm_rot_tentative));
+ mCtrlShinyRot->setTentative(LLSD(spec_rot_tentative));
+
+ mCtrlTexRot->setValue( editable ? diff_rot_deg : 0.0f);
+ mCtrlShinyRot->setValue(editable ? spec_rot_deg : 0.0f);
+ mCtrlBumpyRot->setValue(editable ? norm_rot_deg : 0.0f);
+ }
+
+ {
+ F32 glow = 0.f;
+ bool identical_glow = false;
+ LLSelectedTE::getGlow(glow,identical_glow);
+
+ mCtrlGlow->setValue(glow);
+ mCtrlGlow->setTentative(!identical_glow);
+ mCtrlGlow->setEnabled(editable);
+ }
+
+ {
+ // Maps from enum to combobox entry index
+ mComboTexGen->selectNthItem(((S32)selected_texgen) >> 1);
+
+ mComboTexGen->setEnabled(editable);
+ mComboTexGen->setTentative(!identical);
+ mLabelTexGen->setEnabled(editable);
+ }
+
+ {
+ U8 fullbright_flag = 0;
+ bool identical_fullbright = false;
+
+ LLSelectedTE::getFullbright(fullbright_flag,identical_fullbright);
+
+ mCheckFullbright->setValue((S32)(fullbright_flag != 0));
+ mCheckFullbright->setEnabled(editable );
+ mCheckFullbright->setTentative(!identical_fullbright);
+
+ // TODO: find a better way to do this without relying on the name -Zi
+ childSetEnabled("panel_material_type_media", !has_pbr_material);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_material_type_media " << !has_pbr_material << LL_ENDL;
+ }
+
+ // Repeats per meter
+ {
+ F32 repeats_diff = 1.f;
+ F32 repeats_norm = 1.f;
+ F32 repeats_spec = 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);
+
+ S32 index = mComboTexGen->getCurrentIndex();
+ bool enabled = editable && (index != 1);
+ bool identical_repeats = true;
+
+ S32 material_selection = getCurrentMaterialType();
+ F32 repeats = 1.0f;
+
+ U32 material_type = MATTYPE_DIFFUSE;
+ if (material_selection == MATMEDIA_MATERIAL)
+ {
+ material_type = getCurrentMatChannel();
+ }
+ // TODO: check if repeats per meter even apply to PBR materials -Zi
+ else if (material_selection == MATMEDIA_PBR)
+ {
+ enabled = editable;
+ material_type = getCurrentPBRChannel();
+ }
+
+ switch (material_type)
+ {
+ default:
+ case MATTYPE_DIFFUSE:
+ {
+ if (material_selection != MATMEDIA_PBR)
+ {
+ enabled = editable && !id.isNull();
+ }
+ identical_repeats = identical_diff_repeats;
+ repeats = repeats_diff;
+ }
+ break;
+
+ case MATTYPE_SPECULAR:
+ {
+ if (material_selection != MATMEDIA_PBR)
+ {
+ enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull())
+ && enable_material_controls); // Materials Alignment
+ }
+ identical_repeats = identical_spec_repeats;
+ repeats = repeats_spec;
+ }
+ break;
+
+ case MATTYPE_NORMAL:
+ {
+ if (material_selection != MATMEDIA_PBR)
+ {
+ enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull())
+ && enable_material_controls); // Materials Alignment
+ }
+ identical_repeats = identical_norm_repeats;
+ repeats = repeats_norm;
+ }
+ break;
+ }
+
+ bool repeats_tentative = !identical_repeats;
+
+ if (force_set_values)
+ {
+ //onCommit, previosly edited element updates related ones
+ mCtrlRpt->forceSetValue(editable ? repeats : 1.0f);
+ }
+ else
+ {
+ mCtrlRpt->setValue(editable ? repeats : 1.0f);
+ }
+ mCtrlRpt->setTentative(LLSD(repeats_tentative));
+ mCtrlRpt->setEnabled(!identical_planar_texgen && enabled);
+ }
+
+ // Blinn-Phong Materials
+ {
+ LLMaterialPtr material;
+ LLSelectedTEMaterial::getCurrent(material, identical);
+
+ mComboShininess->setTentative(!identical_spec);
+ mCtrlGlossiness->setTentative(!identical_spec);
+ mCtrlEnvironment->setTentative(!identical_spec);
+ mShinyColorSwatch->setTentative(!identical_spec);
+
+ if (material && editable)
+ {
+ LL_DEBUGS("Materials") << material->asLLSD() << LL_ENDL;
+
+ // Alpha
+ U32 alpha_mode = material->getDiffuseAlphaMode();
+
+ if (transparency > 0.f)
+ { //it is invalid to have any alpha mode other than blend if transparency is greater than zero ...
+ alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+ }
+
+ if (!mIsAlpha)
+ { // ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none
+ alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+ }
+
+ mComboAlphaMode->selectNthItem(alpha_mode);
+
+ mCtrlMaskCutoff->setValue(material->getAlphaMaskCutoff());
+
+ updateAlphaControls();
+
+ identical_planar_texgen = isIdenticalPlanarTexgen();
+
+ // Shiny (specular)
+ F32 offset_x, offset_y, repeat_x, repeat_y, rot;
+
+ mShinyTextureCtrl->setImageAssetID(material->getSpecularID());
+
+ if (material->getSpecularID().notNull() && (shiny == SHINY_TEXTURE))
+ {
+ material->getSpecularOffset(offset_x,offset_y);
+ material->getSpecularRepeat(repeat_x,repeat_y);
+
+ if (identical_planar_texgen)
+ {
+ repeat_x *= 2.0f;
+ repeat_y *= 2.0f;
+ }
+
+ rot = material->getSpecularRotation();
+ mCtrlShinyScaleU->setValue(repeat_x);
+ mCtrlShinyScaleV->setValue(repeat_y);
+ mCtrlShinyRot->setValue(rot*RAD_TO_DEG);
+ mCtrlShinyOffsetU->setValue(offset_x);
+ mCtrlShinyOffsetV->setValue(offset_y);
+ mCtrlGlossiness->setValue(material->getSpecularLightExponent());
+ mCtrlEnvironment->setValue(material->getEnvironmentIntensity());
+
+ updateShinyControls(!material->getSpecularID().isNull(), true);
+ }
+
+ // Assert desired colorswatch color to match material AFTER updateShinyControls
+ // to avoid getting overwritten with the default on some UI state changes.
+ //
+ if (material->getSpecularID().notNull())
+ {
+ LLColor4 new_color = material->getSpecularLightColor();
+ LLColor4 old_color = mShinyColorSwatch->get();
+
+ mShinyColorSwatch->setOriginal(new_color);
+ mShinyColorSwatch->set(new_color, force_set_values || old_color != new_color || !editable);
+ }
+
+ // Bumpy (normal)
+ mBumpyTextureCtrl->setImageAssetID(material->getNormalID());
+
+ if (material->getNormalID().notNull())
+ {
+ material->getNormalOffset(offset_x,offset_y);
+ material->getNormalRepeat(repeat_x,repeat_y);
+
+ if (identical_planar_texgen)
+ {
+ repeat_x *= 2.0f;
+ repeat_y *= 2.0f;
+ }
+
+ rot = material->getNormalRotation();
+ mCtrlBumpyScaleU->setValue(repeat_x);
+ mCtrlBumpyScaleV->setValue(repeat_y);
+ mCtrlBumpyRot->setValue(rot*RAD_TO_DEG);
+ mCtrlBumpyOffsetU->setValue(offset_x);
+ mCtrlBumpyOffsetV->setValue(offset_y);
+
+ updateBumpyControls(!material->getNormalID().isNull(), true);
+ }
+ }
+ }
+
+ S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ bool single_volume = (selected_count == 1);
+ mBtnCopyFaces->setEnabled(editable && single_volume);
+ mBtnPasteFaces->setEnabled(editable && !mClipboardParams.emptyMap() && (mClipboardParams.has("color") || mClipboardParams.has("texture")));
+
+ // Set variable values for numeric expressions
+ LLCalc* calcp = LLCalc::getInstance();
+ calcp->setVar(LLCalc::TEX_U_SCALE, getCurrentTextureScaleU());
+ calcp->setVar(LLCalc::TEX_V_SCALE, getCurrentTextureScaleV());
+ calcp->setVar(LLCalc::TEX_U_OFFSET, getCurrentTextureOffsetU());
+ calcp->setVar(LLCalc::TEX_V_OFFSET, getCurrentTextureOffsetV());
+ calcp->setVar(LLCalc::TEX_ROTATION, getCurrentTextureRot());
+ calcp->setVar(LLCalc::TEX_TRANSPARENCY, mCtrlColorTransp->getValue().asReal());
+ calcp->setVar(LLCalc::TEX_GLOW, mCtrlGlow->getValue().asReal());
+
+ // Find all faces with same texture
+ // TODO: these were not yet added to the new texture panel -Zi
+ /*
+ getChild("btn_select_same_diff")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mTextureCtrl->getEnabled());
+ getChild("btn_select_same_norm")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mBumpyTextureCtrl->getEnabled());
+ getChild("btn_select_same_spec")->setEnabled(LLSelectMgr::getInstance()->getTEMode() && mShinyTextureCtrl->getEnabled());
+ */
+ }
+ else
+ {
+ // we can not edit this object's faces or there is no object selected, so
+ // we can just as well blank out the whole thing. -Zi
+ gSavedSettings.setBOOL("FSInternalCanEditObjectFaces", false);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "hide face edit controls" << LL_ENDL;
+ }
+}
+
+// One-off listener that updates the build floater UI when the agent inventory adds or removes an item
+// TODO: CHECK - Why do we even have this? -Zi
+class PBRPickerAgentListener : public LLInventoryObserver
+{
+protected:
+ bool mChangePending = true;
+public:
+ PBRPickerAgentListener() : LLInventoryObserver()
+ {
+ gInventory.addObserver(this);
+ }
+
+ const bool isListening()
+ {
+ return mChangePending;
+ }
+
+ void changed(U32 mask) override
+ {
+ if (!(mask & (ADD | REMOVE)))
+ {
+ return;
+ }
+
+ if (gFloaterTools)
+ {
+ gFloaterTools->dirty();
+ }
+ gInventory.removeObserver(this);
+ mChangePending = false;
+ }
+
+ ~PBRPickerAgentListener() override
+ {
+ gInventory.removeObserver(this);
+ mChangePending = false;
+ }
+};
+
+// One-off listener that updates the build floater UI when the prim inventory updates
+// TODO: CHECK - Why do we even have this? -Zi
+class PBRPickerObjectListener : public LLVOInventoryListener
+{
+ protected:
+ LLViewerObject* mObjectp;
+ bool mChangePending = true;
+
+ public:
+ PBRPickerObjectListener(LLViewerObject* object)
+ : mObjectp(object)
+ {
+ registerVOInventoryListener(mObjectp, nullptr);
+ }
+
+ const bool isListeningFor(const LLViewerObject* objectp) const
+ {
+ return mChangePending && (objectp == mObjectp);
+ }
+
+ void inventoryChanged(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* user_data) override
+ {
+ if (gFloaterTools)
+ {
+ gFloaterTools->dirty();
+ }
+ removeVOInventoryListener();
+ mChangePending = false;
+ }
+
+ ~PBRPickerObjectListener()
+ {
+ removeVOInventoryListener();
+ mChangePending = false;
+ }
+};
+
+void FSPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values)
+{
+ const bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable();
+
+ mTabsPBRMatMedia->enableTabButton(
+ mTabsPBRMatMedia->getIndexForPanel(
+ mTabsPBRMatMedia->getPanelByName("panel_material_type_pbr")), has_pbr_capabilities);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_material_type_pbr " << has_pbr_capabilities << LL_ENDL;
+
+ LLSelectedTEGetmatId func;
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+
+ has_pbr_material = func.mHasFacesWithPBR;
+ has_faces_without_pbr = func.mHasFacesWithoutPBR;
+
+ // this could just be saved in the class instead of fetching it again after updateUI() already did -Zi
+ const bool settable = has_pbr_capabilities && objectp->permModify() && !objectp->isPermanentEnforced(); // do not depend on non-PBR here so we can turn any face into PBR -Zi
+ const bool editable = LLMaterialEditor::canModifyObjectsMaterial() && !has_faces_without_pbr;
+ const bool saveable = LLMaterialEditor::canSaveObjectsMaterial() && !has_faces_without_pbr;
+
+ mMaterialCtrlPBR->setEnabled(settable);
+ mMaterialCtrlPBR->setTentative(!func.mIdenticalMaterial);
+ mMaterialCtrlPBR->setImageAssetID(func.mMaterialId);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "mMaterialCtrlPBR " << settable << LL_ENDL;
+
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "PBR controls overall: " << editable << LL_ENDL;
+
+ mBaseTexturePBR->setEnabled(editable);
+ mBaseTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] : LLUUID::null);
+ mBaseTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]);
+
+ mBaseTintPBR->setEnabled(editable);
+
+ mBaseTintPBR->set(srgbColor4(func.mMaterialSummary.mBaseColor));
+ mBaseTintPBR->setTentative(!func.mIdenticalBaseColor); // TODO: split alpha from color? -Zi
+ mBaseTintPBR->setValid(editable);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "mBaseTintPBR valid " << editable << LL_ENDL;
+ mBaseTintPBR->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
+
+ mNormalTexturePBR->setEnabled(editable);
+ mNormalTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] : LLUUID::null);
+ mNormalTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]);
+
+ mORMTexturePBR->setEnabled(editable);
+ mORMTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] : LLUUID::null);
+ mORMTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]);
+
+ mEmissiveTexturePBR->setEnabled(editable);
+ mEmissiveTexturePBR->setImageAssetID(editable ? func.mMaterialSummary.mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] : LLUUID::null);
+ mEmissiveTexturePBR->setTentative(!func.mIdenticalMap[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]);
+
+ mEmissiveTintPBR->setEnabled(editable);
+ mEmissiveTintPBR->set(srgbColor4(func.mMaterialSummary.mEmissiveColor));
+ mEmissiveTintPBR->setTentative(!func.mIdenticalEmissive);
+ mEmissiveTintPBR->setValid(editable);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "mEmissiveTintPBR valid " << editable << LL_ENDL;
+ mEmissiveTintPBR->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
+
+ mCheckDoubleSidedPBR->setEnabled(editable);
+ mCheckDoubleSidedPBR->setValue(func.mMaterialSummary.mDoubleSided);
+ mCheckDoubleSidedPBR->setTentative(!func.mIdenticalDoubleSided);
+
+ mAlphaPBR->setEnabled(editable);
+ mAlphaPBR->setValue(func.mMaterialSummary.mBaseColor.mV[VALPHA]);
+ mAlphaPBR->setTentative(!func.mIdenticalBaseColor); // TODO: split alpha from color? -Zi
+
+ mAlphaModePBR->setEnabled(editable);
+ mAlphaModePBR->setValue(func.mMaterialSummary.getAlphaMode());
+ mAlphaModePBR->setTentative(!func.mIdenticalAlphaMode);
+ mLabelAlphaModePBR->setEnabled(editable);
+
+ mMaskCutoffPBR->setEnabled(editable);
+ mMaskCutoffPBR->setValue(func.mMaterialSummary.mAlphaCutoff);
+ mMaskCutoffPBR->setTentative(!func.mIdenticalAlphaCutoff);
+
+ mMetallicFactorPBR->setEnabled(editable);
+ mMetallicFactorPBR->setValue(func.mMaterialSummary.mMetallicFactor);
+ mMetallicFactorPBR->setTentative(!func.mIdenticalMetallic);
+
+ mRoughnessFactorPBR->setEnabled(editable);
+ mRoughnessFactorPBR->setValue(func.mMaterialSummary.mRoughnessFactor);
+ mRoughnessFactorPBR->setTentative(!func.mIdenticalRoughness);
+
+ if (func.mMaterial)
+ {
+ mPBRBaseMaterialParams.mMap = func.mMaterial->mTextureId;
+ mPBRBaseMaterialParams.mBaseColorTint = srgbColor4(func.mMaterial->mBaseColor);
+ mPBRBaseMaterialParams.mMetallic = func.mMaterial->mMetallicFactor;
+ mPBRBaseMaterialParams.mRoughness = func.mMaterial->mRoughnessFactor;
+ mPBRBaseMaterialParams.mEmissiveTint = func.mMaterial->mEmissiveColor;
+ mPBRBaseMaterialParams.mAlphaMode = func.mMaterial->mAlphaMode;
+ mPBRBaseMaterialParams.mAlphaCutoff = func.mMaterial->mAlphaCutoff;
+ mPBRBaseMaterialParams.mDoubleSided = func.mMaterial->mDoubleSided;
+ }
+
+ if (objectp->isAttachment())
+ {
+ // TODO: coming in from latest patch, seems broken?
+ mMaterialCtrlPBR->setFilterPermissionMasks(PERM_COPY | PERM_TRANSFER | PERM_MODIFY);
+ // TODO: before:
+ // mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER | PERM_MODIFY);
+ }
+ else
+ {
+ mMaterialCtrlPBR->setImmediateFilterPermMask(PERM_NONE);
+ }
+
+ mBtnSavePBR->setEnabled(saveable); // TODO: flag for "something is not identical" -Zi && pbr_identical);
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "mBtnSavePBR " << saveable << LL_ENDL;
+
+ // TODO: CHECK - Find out if we need this at all -Zi
+ if (objectp->isInventoryPending())
+ {
+ // Reuse the same listener when possible
+ if (!mVOInventoryListener || !mVOInventoryListener->isListeningFor(objectp))
+ {
+ mVOInventoryListener = std::make_unique(objectp);
+ }
+ }
+ else
+ {
+ mVOInventoryListener = nullptr;
+ }
+ if (!func.mIdenticalMaterial || func.mMaterialId.isNull() || func.mMaterialId == LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID)
+ {
+ mAgentInventoryListener = nullptr;
+ }
+ else
+ {
+ if (!mAgentInventoryListener || !mAgentInventoryListener->isListening())
+ {
+ mAgentInventoryListener = std::make_unique();
+ }
+ }
+
+ // Control values will be set once per frame in setMaterialOverridesFromSelection
+ sMaterialOverrideSelection.setDirty();
+}
+
+void FSPanelFace::updateCopyTexButton()
+{
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+
+ mBtnCopyFaces->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify()
+ && !objectp->isPermanentEnforced() && !objectp->isInventoryPending()
+ && (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1)
+ && LLMaterialEditor::canClipboardObjectsMaterial());
+ std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
+ mBtnCopyFaces->setToolTip(tooltip);
+}
+
+void FSPanelFace::refresh()
+{
+ LL_DEBUGS("Materials") << LL_ENDL;
+ getState();
+}
+
+void FSPanelFace::refreshMedia()
+{
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+ LLViewerObject* first_object = selected_objects->getFirstObject();
+
+ if (!(first_object
+ && first_object->getPCode() == LL_PCODE_VOLUME
+ && first_object->permModify()
+ ))
+ {
+ mBtnAddMedia->setEnabled(false);
+ mTitleMediaText->clear();
+ clearMediaSettings();
+ return;
+ }
+
+ std::string url = first_object->getRegion()->getCapability("ObjectMedia");
+ bool has_media_capability = (!url.empty());
+
+ if (!has_media_capability)
+ {
+ mBtnAddMedia->setEnabled(false);
+ LL_WARNS("LLFloaterToolsMedia") << "Media not enabled (no capability) in this region!" << LL_ENDL;
+ clearMediaSettings();
+ return;
+ }
+
+ bool is_nonpermanent_enforced = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode()
+ && LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced())
+ || LLSelectMgr::getInstance()->selectGetNonPermanentEnforced();
+ bool editable = is_nonpermanent_enforced && (first_object->permModify() || selectedMediaEditable());
+
+ // Check modify permissions and whether any selected objects are in
+ // the process of being fetched. If they are, then we're not editable
+ if (editable)
+ {
+ LLObjectSelection::iterator iter = selected_objects->begin();
+ LLObjectSelection::iterator end = selected_objects->end();
+ for (; iter != end; ++iter)
+ {
+ LLSelectNode* node = *iter;
+ LLVOVolume* object = dynamic_cast(node->getObject());
+ if (object && !object->permModify())
+ {
+ LL_INFOS("LLFloaterToolsMedia")
+ << "Selection not editable due to lack of modify permissions on object id "
+ << object->getID() << LL_ENDL;
+
+ editable = false;
+ break;
+ }
+ }
+ }
+
+ // Media settings
+ bool bool_has_media = false;
+ struct media_functor : public LLSelectedTEGetFunctor
+ {
+ bool get(LLViewerObject* object, S32 face)
+ {
+ LLTextureEntry *te = object->getTE(face);
+ if (te)
+ {
+ return te->hasMedia();
+ }
+ return false;
+ }
+ } func;
+
+ // check if all faces have media (or, all don't have media)
+ LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media);
+
+ const LLMediaEntry default_media_data;
+
+ struct functor_getter_media_data : public LLSelectedTEGetFunctor< LLMediaEntry>
+ {
+ functor_getter_media_data(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ LLMediaEntry get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return *(object->getTE(face)->getMediaData());
+ }
+ return mMediaEntry;
+ };
+
+ const LLMediaEntry& mMediaEntry;
+
+ } func_media_data(default_media_data);
+
+ LLMediaEntry media_data_get;
+ LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get));
+
+ std::string multi_media_info_str = LLTrans::getString("Multiple Media");
+ std::string media_title = "";
+
+ // update UI depending on whether "object" (prim or face) has media
+ // and whether or not you are allowed to edit it.
+
+ mBtnAddMedia->setEnabled(editable);
+
+ // IF all the faces have media (or all don't have media)
+ if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo)
+ {
+ // 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))
+ {
+ // media data is valid
+ if (media_data_get != default_media_data)
+ {
+ // initial media title is the media URL (until we get the name)
+ media_title = media_data_get.getHomeURL();
+ }
+ // else all faces might be empty
+ }
+ else // there are Different media been set on on the faces
+ {
+ media_title = multi_media_info_str;
+ }
+
+ mBtnDeleteMedia->setEnabled(bool_has_media && editable);
+
+ // TODO: display a list of all media on the face - use 'identical' flag
+ }
+ else // not all faces have media but at least one does
+ {
+ // selected faces have not identical value
+ LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
+
+ if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
+ {
+ media_title = multi_media_info_str;
+ }
+ else
+ {
+ // Media data is valid
+ if (media_data_get != default_media_data)
+ {
+ // initial media title is the media URL (until we get the name)
+ media_title = media_data_get.getHomeURL();
+ }
+ }
+
+ mBtnDeleteMedia->setEnabled(TRUE);
+ }
+
+ S32 materials_media = getCurrentMaterialType();
+ if (materials_media == MATMEDIA_MEDIA)
+ {
+ // currently displaying media info, navigateTo and update title
+ navigateToTitleMedia(media_title);
+ }
+ else
+ {
+ // Media can be heavy, don't keep it around
+ // MAC specific: MAC doesn't support setVolume(0) so if not
+ // unloaded, it might keep playing audio until user closes editor
+ unloadMedia();
+ mNeedMediaTitle = false;
+ }
+
+ mTitleMediaText->setText(media_title);
+
+ // load values for media settings
+ updateMediaSettings();
+
+ LLFloaterMediaSettings::initValues(mMediaSettings, editable);
+}
+
+void FSPanelFace::unloadMedia()
+{
+ // destroy media source used to grab media title
+ mTitleMedia->unloadMediaSource();
+}
+
+void FSPanelFace::onMaterialOverrideReceived(const LLUUID& object_id, S32 side)
+{
+ sMaterialOverrideSelection.onSelectedObjectUpdated(object_id, side);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+void FSPanelFace::navigateToTitleMedia(const std::string url)
+{
+ std::string multi_media_info_str = LLTrans::getString("Multiple Media");
+ if (url.empty() || multi_media_info_str == url)
+ {
+ // nothing to show
+ mNeedMediaTitle = false;
+ }
+ else
+ {
+ LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
+
+ // check if url changed or if we need a new media source
+ if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == nullptr)
+ {
+ mTitleMedia->navigateTo(url);
+
+ LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mTitleMedia->getTextureID());
+ if (impl)
+ {
+ // if it's a page with a movie, we don't want to hear it
+ impl->setVolume(0);
+ }
+ }
+
+ // flag that we need to update the title (even if no request were made)
+ mNeedMediaTitle = true;
+ }
+}
+
+bool FSPanelFace::selectedMediaEditable()
+{
+ U32 owner_mask_on;
+ U32 owner_mask_off;
+ U32 valid_owner_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER,
+ &owner_mask_on, &owner_mask_off);
+ U32 group_mask_on;
+ U32 group_mask_off;
+ U32 valid_group_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_GROUP,
+ &group_mask_on, &group_mask_off);
+ U32 everyone_mask_on;
+ U32 everyone_mask_off;
+ S32 valid_everyone_perms = LLSelectMgr::getInstance()->selectGetPerm(PERM_EVERYONE,
+ &everyone_mask_on, &everyone_mask_off);
+
+ bool selected_Media_editable = false;
+
+ // if perms we got back are valid
+ if (valid_owner_perms &&
+ valid_group_perms &&
+ valid_everyone_perms)
+ {
+ if ((owner_mask_on & PERM_MODIFY) ||
+ (group_mask_on & PERM_MODIFY) ||
+ (everyone_mask_on & PERM_MODIFY))
+ {
+ selected_Media_editable = true;
+ }
+ else
+ {
+ // user is NOT allowed to press the RESET button
+ selected_Media_editable = false;
+ };
+ };
+
+ return selected_Media_editable;
+}
+
+void FSPanelFace::clearMediaSettings()
+{
+ LLFloaterMediaSettings::clearValues(false);
+}
+
+void FSPanelFace::updateMediaSettings()
+{
+ bool identical(false);
+ std::string base_key("");
+ std::string value_str("");
+ int value_int = 0;
+ bool value_bool = false;
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+ // TODO: (CP) refactor this using something clever or boost or both !!
+
+ const LLMediaEntry default_media_data;
+
+ // controls
+ U8 value_u8 = default_media_data.getControls();
+ struct functor_getter_controls : public LLSelectedTEGetFunctor
+ {
+ functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {}
+
+ U8 get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getControls();
+ }
+ return mMediaEntry.getControls();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_controls(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_controls, value_u8);
+ base_key = std::string(LLMediaEntry::CONTROLS_KEY);
+ mMediaSettings[base_key] = value_u8;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // First click (formerly left click)
+ value_bool = default_media_data.getFirstClickInteract();
+ struct functor_getter_first_click : public LLSelectedTEGetFunctor
+ {
+ functor_getter_first_click(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getFirstClickInteract();
+ }
+ return mMediaEntry.getFirstClickInteract();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+ } func_first_click(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_first_click, value_bool);
+ base_key = std::string(LLMediaEntry::FIRST_CLICK_INTERACT_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Home URL
+ value_str = default_media_data.getHomeURL();
+ struct functor_getter_home_url : public LLSelectedTEGetFunctor
+ {
+ functor_getter_home_url(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ std::string get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getHomeURL();
+ }
+ return mMediaEntry.getHomeURL();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_home_url(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_home_url, value_str);
+ base_key = std::string(LLMediaEntry::HOME_URL_KEY);
+ mMediaSettings[base_key] = value_str;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Current URL
+ value_str = default_media_data.getCurrentURL();
+ struct functor_getter_current_url : public LLSelectedTEGetFunctor
+ {
+ functor_getter_current_url(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ std::string get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getCurrentURL();
+ }
+ return mMediaEntry.getCurrentURL();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+ } func_current_url(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_current_url, value_str);
+ base_key = std::string(LLMediaEntry::CURRENT_URL_KEY);
+ mMediaSettings[base_key] = value_str;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Auto zoom
+ value_bool = default_media_data.getAutoZoom();
+ struct functor_getter_auto_zoom : public LLSelectedTEGetFunctor
+ {
+ functor_getter_auto_zoom(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getAutoZoom();
+ }
+ return mMediaEntry.getAutoZoom();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+ } func_auto_zoom(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_auto_zoom, value_bool);
+ base_key = std::string(LLMediaEntry::AUTO_ZOOM_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Auto play
+ //value_bool = default_media_data.getAutoPlay();
+ // set default to auto play TRUE -- angela EXT-5172
+ value_bool = true;
+ struct functor_getter_auto_play : public LLSelectedTEGetFunctor
+ {
+ functor_getter_auto_play(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getAutoPlay();
+ }
+ //return mMediaEntry.getAutoPlay(); set default to auto play TRUE -- angela EXT-5172
+ return true;
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_auto_play(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_auto_play, value_bool);
+ base_key = std::string(LLMediaEntry::AUTO_PLAY_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+
+ // Auto scale
+ // set default to auto scale TRUE -- angela EXT-5172
+ //value_bool = default_media_data.getAutoScale();
+ value_bool = true;
+ struct functor_getter_auto_scale : public LLSelectedTEGetFunctor
+ {
+ functor_getter_auto_scale(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getAutoScale();
+ }
+ // return mMediaEntry.getAutoScale(); set default to auto scale TRUE -- angela EXT-5172
+ return true;
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_auto_scale(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_auto_scale, value_bool);
+ base_key = std::string(LLMediaEntry::AUTO_SCALE_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Auto loop
+ value_bool = default_media_data.getAutoLoop();
+ struct functor_getter_auto_loop : public LLSelectedTEGetFunctor
+ {
+ functor_getter_auto_loop(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getAutoLoop();
+ }
+ return mMediaEntry.getAutoLoop();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_auto_loop(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_auto_loop, value_bool);
+ base_key = std::string(LLMediaEntry::AUTO_LOOP_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // width pixels (if not auto scaled)
+ value_int = default_media_data.getWidthPixels();
+ struct functor_getter_width_pixels : public LLSelectedTEGetFunctor
+ {
+ functor_getter_width_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ int get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getWidthPixels();
+ }
+ return mMediaEntry.getWidthPixels();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_width_pixels(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_width_pixels, value_int);
+ base_key = std::string(LLMediaEntry::WIDTH_PIXELS_KEY);
+ mMediaSettings[base_key] = value_int;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // height pixels (if not auto scaled)
+ value_int = default_media_data.getHeightPixels();
+ struct functor_getter_height_pixels : public LLSelectedTEGetFunctor
+ {
+ functor_getter_height_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ int get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getHeightPixels();
+ }
+ return mMediaEntry.getHeightPixels();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_height_pixels(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_height_pixels, value_int);
+ base_key = std::string(LLMediaEntry::HEIGHT_PIXELS_KEY);
+ mMediaSettings[base_key] = value_int;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Enable Alt image
+ value_bool = default_media_data.getAltImageEnable();
+ struct functor_getter_enable_alt_image : public LLSelectedTEGetFunctor
+ {
+ functor_getter_enable_alt_image(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getAltImageEnable();
+ }
+ return mMediaEntry.getAltImageEnable();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_enable_alt_image(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_enable_alt_image, value_bool);
+ base_key = std::string(LLMediaEntry::ALT_IMAGE_ENABLE_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Perms - owner interact
+ value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_OWNER);
+ struct functor_getter_perms_owner_interact : public LLSelectedTEGetFunctor
+ {
+ functor_getter_perms_owner_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_OWNER));
+ }
+ return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_OWNER);
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_perms_owner_interact(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_perms_owner_interact, value_bool);
+ base_key = std::string(LLPanelContents::PERMS_OWNER_INTERACT_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Perms - owner control
+ value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_OWNER);
+ struct functor_getter_perms_owner_control : public LLSelectedTEGetFunctor
+ {
+ functor_getter_perms_owner_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_OWNER));
+ }
+ return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_OWNER);
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_perms_owner_control(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_perms_owner_control, value_bool);
+ base_key = std::string(LLPanelContents::PERMS_OWNER_CONTROL_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Perms - group interact
+ value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_GROUP);
+ struct functor_getter_perms_group_interact : public LLSelectedTEGetFunctor
+ {
+ functor_getter_perms_group_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_GROUP));
+ }
+ return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_GROUP);
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_perms_group_interact(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_perms_group_interact, value_bool);
+ base_key = std::string(LLPanelContents::PERMS_GROUP_INTERACT_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Perms - group control
+ value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_GROUP);
+ struct functor_getter_perms_group_control : public LLSelectedTEGetFunctor
+ {
+ functor_getter_perms_group_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_GROUP));
+ }
+ return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_GROUP);
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_perms_group_control(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_perms_group_control, value_bool);
+ base_key = std::string(LLPanelContents::PERMS_GROUP_CONTROL_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Perms - anyone interact
+ value_bool = 0 != (default_media_data.getPermsInteract() & LLMediaEntry::PERM_ANYONE);
+ struct functor_getter_perms_anyone_interact : public LLSelectedTEGetFunctor
+ {
+ functor_getter_perms_anyone_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return (0 != (object->getTE(face)->getMediaData()->getPermsInteract() & LLMediaEntry::PERM_ANYONE));
+ }
+ return 0 != (mMediaEntry.getPermsInteract() & LLMediaEntry::PERM_ANYONE);
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_perms_anyone_interact(default_media_data);
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func_perms_anyone_interact, value_bool);
+ base_key = std::string(LLPanelContents::PERMS_ANYONE_INTERACT_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // Perms - anyone control
+ value_bool = 0 != (default_media_data.getPermsControl() & LLMediaEntry::PERM_ANYONE);
+ struct functor_getter_perms_anyone_control : public LLSelectedTEGetFunctor
+ {
+ functor_getter_perms_anyone_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return (0 != (object->getTE(face)->getMediaData()->getPermsControl() & LLMediaEntry::PERM_ANYONE));
+ }
+ return 0 != (mMediaEntry.getPermsControl() & LLMediaEntry::PERM_ANYONE);
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_perms_anyone_control(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_perms_anyone_control, value_bool);
+ base_key = std::string(LLPanelContents::PERMS_ANYONE_CONTROL_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // security - whitelist enable
+ value_bool = default_media_data.getWhiteListEnable();
+ struct functor_getter_whitelist_enable : public LLSelectedTEGetFunctor
+ {
+ functor_getter_whitelist_enable(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ bool get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getWhiteListEnable();
+ }
+ return mMediaEntry.getWhiteListEnable();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_whitelist_enable(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_whitelist_enable, value_bool);
+ base_key = std::string(LLMediaEntry::WHITELIST_ENABLE_KEY);
+ mMediaSettings[base_key] = value_bool;
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+
+ // security - whitelist URLs
+ std::vector value_vector_str = default_media_data.getWhiteList();
+ struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor>
+ {
+ functor_getter_whitelist_urls(const LLMediaEntry& entry) : mMediaEntry(entry) {}
+
+ std::vector get(LLViewerObject* object, S32 face)
+ {
+ if (object && object->getTE(face) && object->getTE(face)->getMediaData())
+ {
+ return object->getTE(face)->getMediaData()->getWhiteList();
+ }
+ return mMediaEntry.getWhiteList();
+ };
+
+ const LLMediaEntry &mMediaEntry;
+
+ } func_whitelist_urls(default_media_data);
+
+ identical = selected_objects->getSelectedTEValue(&func_whitelist_urls, value_vector_str);
+ base_key = std::string(LLMediaEntry::WHITELIST_KEY);
+ mMediaSettings[base_key].clear();
+
+ std::vector< std::string >::iterator iter = value_vector_str.begin();
+ while (iter != value_vector_str.end())
+ {
+ std::string white_list_url = *iter;
+ mMediaSettings[base_key].append(white_list_url);
+ ++iter;
+ };
+
+ mMediaSettings[base_key + std::string(LLPanelContents::TENTATIVE_SUFFIX)] = !identical;
+}
+
+void FSPanelFace::updateMediaTitle()
+{
+ // only get the media name if we need it
+ if (!mNeedMediaTitle)
+ {
+ return;
+ }
+
+ // get plugin impl
+ LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
+ if (media_plugin && mTitleMedia->getCurrentNavUrl() == media_plugin->getNavigateURI())
+ {
+ // get the media name (asynchronous - must call repeatedly)
+ std::string media_title = media_plugin->getMediaName();
+
+ // only replace the title if what we get contains something
+ if (!media_title.empty())
+ {
+ // update the UI widget
+ mTitleMediaText->setText(media_title);
+
+ // stop looking for a title when we get one
+ mNeedMediaTitle = false;
+ }
+ }
+}
+
+void FSPanelFace::onCommitColor()
+{
+ sendColor();
+}
+
+void FSPanelFace::onCommitShinyColor()
+{
+ LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get());
+}
+
+void FSPanelFace::onCommitAlpha()
+{
+ sendAlpha();
+}
+
+void FSPanelFace::onCancelColor()
+{
+ LLSelectMgr::getInstance()->selectionRevertColors();
+}
+
+void FSPanelFace::onCancelShinyColor()
+{
+ LLSelectMgr::getInstance()->selectionRevertShinyColors();
+}
+
+void FSPanelFace::onSelectColor()
+{
+ LLSelectMgr::getInstance()->saveSelectedObjectColors();
+ sendColor();
+}
+
+void FSPanelFace::onSelectShinyColor()
+{
+ LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get());
+ LLSelectMgr::getInstance()->saveSelectedShinyColors();
+}
+
+void FSPanelFace::updateVisibility(LLViewerObject* objectp /* = nullptr */)
+{
+ updateAlphaControls();
+ // TODO: is this still needed? -Zi
+ updateShinyControls();
+ updateBumpyControls();
+
+ // Find all faces with same texture
+ // TODO: is this still needed? -Zi Probably not but we don't have these buttons yet anyway -Zi
+ /*
+ getChild("btn_select_same_diff")->setVisible(mTextureCtrl->getVisible());
+ getChild("btn_select_same_norm")->setVisible(mBumpyTextureCtrl->getVisible());
+ getChild("btn_select_same_spec")->setVisible(mShinyTextureCtrl->getVisible());
+ */
+}
+
+void FSPanelFace::onCommitBump()
+{
+ sendBump(mComboBumpiness->getCurrentIndex());
+}
+
+void FSPanelFace::onCommitTexGen()
+{
+ sendTexGen();
+}
+
+void FSPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_shiny_combobox)
+{
+ LLUUID shiny_texture_ID = mShinyTextureCtrl->getImageAssetID();
+ LL_DEBUGS("Materials") << "Shiny texture selected: " << shiny_texture_ID << LL_ENDL;
+
+ if(mess_with_shiny_combobox)
+ {
+ if (shiny_texture_ID.notNull() && is_setting_texture)
+ {
+ if (!mComboShininess->itemExists(USE_TEXTURE_LABEL))
+ {
+ mComboShininess->add(USE_TEXTURE_LABEL);
+ }
+ mComboShininess->setSimple(USE_TEXTURE_LABEL);
+ }
+ else
+ {
+ if (mComboShininess->itemExists(USE_TEXTURE_LABEL))
+ {
+ mComboShininess->remove(SHINY_TEXTURE);
+ mComboShininess->selectFirstItem();
+ }
+ }
+ }
+ else
+ {
+ if (shiny_texture_ID.isNull() && mComboShininess->itemExists(USE_TEXTURE_LABEL))
+ {
+ mComboShininess->remove(SHINY_TEXTURE);
+ mComboShininess->selectFirstItem();
+ }
+ }
+
+ mShinyColorSwatch->setValid(shiny_texture_ID.notNull());
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "mShinyColorSwatch valid " << shiny_texture_ID.notNull() << LL_ENDL;
+ mShinyColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c"));
+
+ gSavedSettings.setBOOL("FSInternalFaceHasBPSpecularMap", shiny_texture_ID.notNull());
+
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_blinn_phong_specular " << shiny_texture_ID.notNull() << LL_ENDL;
+}
+
+void FSPanelFace::updateBumpyControls(bool is_setting_texture, bool mess_with_combobox)
+{
+ LLUUID bumpy_texture_ID = mBumpyTextureCtrl->getImageAssetID();
+ LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL;
+
+ if (mess_with_combobox)
+ {
+ LLUUID bumpy_texture_ID = mBumpyTextureCtrl->getImageAssetID();
+ LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL;
+
+ if (bumpy_texture_ID.notNull() && is_setting_texture)
+ {
+ if (!mComboBumpiness->itemExists(USE_TEXTURE_LABEL))
+ {
+ mComboBumpiness->add(USE_TEXTURE_LABEL);
+ }
+ mComboBumpiness->setSimple(USE_TEXTURE_LABEL);
+ }
+ else
+ {
+ if (mComboBumpiness->itemExists(USE_TEXTURE_LABEL))
+ {
+ mComboBumpiness->remove(BUMPY_TEXTURE);
+ mComboBumpiness->selectFirstItem();
+ }
+ }
+ }
+
+ gSavedSettings.setBOOL("FSInternalFaceHasBPNormalMap", bumpy_texture_ID.notNull());
+
+ LL_DEBUGS("ENABLEDISABLETOOLS") << "panel_blinn_phong_normal " << bumpy_texture_ID.notNull() << LL_ENDL;
+}
+
+void FSPanelFace::onCommitShiny()
+{
+ sendShiny(mComboShininess->getCurrentIndex());
+}
+
+void FSPanelFace::updateAlphaControls()
+{
+ mCtrlMaskCutoff->setEnabled(getCurrentDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK);
+}
+
+void FSPanelFace::onCommitAlphaMode()
+{
+ updateAlphaControls();
+ LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode());
+}
+
+void FSPanelFace::onCommitFullbright()
+{
+ sendFullbright();
+}
+
+void FSPanelFace::onCommitGlow()
+{
+ sendGlow();
+}
+
+//
+// PBR
+//
+
+// Get a dump of the json representation of the current state of the editor UI
+// in GLTF format, excluding transforms as they are not supported in material
+// assets. (See also LLGLTFMaterial::sanitizeAssetMaterial())
+void FSPanelFace::getGLTFMaterial(LLGLTFMaterial* mat)
+{
+ mat->mBaseColor = linearColor4(LLColor4(mBaseTintPBR->get()));
+ mat->mBaseColor.mV[VALPHA] = mAlphaPBR->get();
+
+ mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = mBaseTexturePBR->getImageAssetID();
+ mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = mNormalTexturePBR->getImageAssetID();
+ mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = mORMTexturePBR->getImageAssetID();
+ mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = mEmissiveTexturePBR->getImageAssetID();
+
+ mat->mEmissiveColor = linearColor4(LLColor4(mEmissiveTintPBR->get()));
+
+ mat->mMetallicFactor = mMetallicFactorPBR->get();
+ mat->mRoughnessFactor = mRoughnessFactorPBR->get();
+
+ mat->mDoubleSided = mCheckDoubleSidedPBR->get();
+ mat->setAlphaMode(mAlphaModePBR->getValue().asString());
+ mat->mAlphaCutoff = mMaskCutoffPBR->getValue().asReal();
+}
+
+BOOL FSPanelFace::onDragPbr(LLInventoryItem* item)
+{
+ bool accept = true;
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if (!LLToolDragAndDrop::isInventoryDropAcceptable(obj, item))
+ {
+ accept = false;
+ break;
+ }
+ }
+ return accept;
+}
+
+void FSPanelFace::onCommitPbr()
+{
+ if (!mMaterialCtrlPBR->getTentative())
+ {
+ // we grab the item id first, because we want to do a
+ // permissions check in the selection manager. ARGH!
+ LLUUID id = mMaterialCtrlPBR->getImageItemID();
+ if (id.isNull())
+ {
+ id = mMaterialCtrlPBR->getImageAssetID();
+ }
+ if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
+ {
+ // If failed to set material, refresh mMaterialCtrlPBR's value
+ refresh();
+ }
+ }
+}
+
+void FSPanelFace::onCancelPbr()
+{
+ LLSelectMgr::getInstance()->selectionRevertGLTFMaterials();
+}
+
+void FSPanelFace::onSelectPbr()
+{
+ LLSelectMgr::getInstance()->saveSelectedObjectTextures();
+ onCommitPbr();
+}
+
+void FSPanelFace::onCommitPbr(const LLUICtrl* pbr_ctrl)
+{
+ LL_WARNS("FACEPANELM") << "committed pbr map " << pbr_ctrl->getName() << LL_ENDL;
+
+ if (pbr_ctrl == mBaseTexturePBR)
+ {
+ mUnsavedChanges |= MATERIAL_BASE_COLOR_TEX_DIRTY;
+ }
+ else if (pbr_ctrl == mNormalTexturePBR)
+ {
+ mUnsavedChanges |= MATERIAL_NORMAL_TEX_DIRTY;
+ }
+ else if (pbr_ctrl == mEmissiveTexturePBR)
+ {
+ mUnsavedChanges |= MATERIAL_EMISIVE_TEX_DIRTY;
+ }
+ else if (pbr_ctrl == mORMTexturePBR)
+ {
+ mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY;
+ }
+ else if (pbr_ctrl == mBaseTintPBR)
+ {
+ mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY;
+ }
+ else if (pbr_ctrl == mEmissiveTintPBR)
+ {
+ mUnsavedChanges |= MATERIAL_EMISIVE_COLOR_DIRTY;
+ }
+ else if (pbr_ctrl == mCheckDoubleSidedPBR)
+ {
+ mUnsavedChanges |= MATERIAL_DOUBLE_SIDED_DIRTY;
+ }
+ else if (pbr_ctrl == mAlphaPBR)
+ {
+ mUnsavedChanges |= MATERIAL_BASE_COLOR_DIRTY;
+ }
+ else if (pbr_ctrl == mAlphaModePBR)
+ {
+ mUnsavedChanges |= MATERIAL_ALPHA_MODE_DIRTY;
+ }
+ else if (pbr_ctrl == mMaskCutoffPBR)
+ {
+ mUnsavedChanges |= MATERIAL_ALPHA_CUTOFF_DIRTY;
+ }
+ else if (pbr_ctrl == mMetallicFactorPBR)
+ {
+ mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY;
+ }
+ else if (pbr_ctrl == mRoughnessFactorPBR)
+ {
+ mUnsavedChanges |= MATERIAL_METALLIC_ROUGHTNESS_ROUGHNESS_DIRTY;
+ }
+}
+
+// highlights PBR material parameters that are part of a material override
+void FSPanelFace::updatePBROverrideDisplay()
+{
+ LLColor4 labelTextColor = LLUIColorTable::instance().getColor("LabelTextColor");
+ LLColor4 emphasisColor = LLUIColorTable::instance().getColor("EmphasisColor"); // TODO: maybe create distinct color for skins -Zi
+
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+
+ if (!objectp || !node)
+ {
+ return;
+ }
+
+ // a way to resolve situations where source and target have different amount of faces
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), objectp->getNumFaces());
+ for (S32 te = 0; te < num_tes; ++te)
+ {
+ if (!node->isTESelected(te))
+ {
+ continue;
+ }
+
+ LLTextureEntry* tep = objectp->getTE(te);
+ if (!tep)
+ {
+ continue;
+ }
+
+ LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
+ if (!override_material)
+ {
+ continue;
+ }
+
+ LL_DEBUGS("GET_GLTF_MATERIAL_PARAMS")
+ << override_material << "\n"
+ << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] << "\n"
+ << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] << "\n"
+ << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] << "\n"
+ << override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] << "\n"
+ << override_material->mBaseColor << "\n"
+ << override_material->mEmissiveColor << "\n"
+ << override_material->mAlphaMode << "\n"
+ << override_material->mAlphaCutoff << "\n"
+ << override_material->mMetallicFactor << "\n"
+ << override_material->mRoughnessFactor << "\n"
+ << override_material->mDoubleSided << "\n"
+ << LL_ENDL;
+
+ mBaseTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].isNull() ? labelTextColor : emphasisColor);
+ mNormalTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].isNull() ? labelTextColor : emphasisColor);
+ mORMTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].isNull() ? labelTextColor : emphasisColor);
+ mEmissiveTexturePBR->setLabelColor(override_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].isNull() ? labelTextColor : emphasisColor);
+
+ mBaseTintPBR->setLabelColor(override_material->mBaseColor == LLGLTFMaterial::getDefaultBaseColor() ? labelTextColor : emphasisColor);
+ mAlphaPBR->setLabelColor(override_material->mBaseColor == LLGLTFMaterial::getDefaultBaseColor() ? labelTextColor : emphasisColor);
+ mLabelAlphaModePBR->setColor(override_material->mAlphaMode == LLGLTFMaterial::getDefaultAlphaMode() ? labelTextColor : emphasisColor);
+ mMaskCutoffPBR->setLabelColor(override_material->mAlphaCutoff == LLGLTFMaterial::getDefaultAlphaCutoff() ? labelTextColor : emphasisColor);
+
+ mMetallicFactorPBR->setLabelColor(override_material->mMetallicFactor == LLGLTFMaterial::getDefaultMetallicFactor() ? labelTextColor : emphasisColor);
+ mRoughnessFactorPBR->setLabelColor(override_material->mRoughnessFactor == LLGLTFMaterial::getDefaultRoughnessFactor() ? labelTextColor : emphasisColor);
+
+ mEmissiveTintPBR->setLabelColor(override_material->mEmissiveColor == LLGLTFMaterial::getDefaultEmissiveColor() ? labelTextColor : emphasisColor);
+
+ mCheckDoubleSidedPBR->setEnabledColor(override_material->mDoubleSided == LLGLTFMaterial::getDefaultDoubleSided() ? labelTextColor : emphasisColor);
+ // refresh checkbox, as LLCheckBoxCtrl does not refresh its label when you change the color
+ mCheckDoubleSidedPBR->setEnabled(mCheckDoubleSidedPBR->getEnabled());
+
+ break;
+ }
+}
+
+void FSPanelFace::onCancelPbr(const LLUICtrl* map_ctrl)
+{
+ // TODO -Zi
+}
+
+void FSPanelFace::onSelectPbr(const LLUICtrl* map_ctrl)
+{
+ onCommitPbr(map_ctrl);
+}
+
+BOOL FSPanelFace::onDragTexture(LLInventoryItem* item)
+{
+ bool accept = true;
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if (!LLToolDragAndDrop::isInventoryDropAcceptable(obj, item))
+ {
+ accept = false;
+ break;
+ }
+ }
+ return accept;
+}
+
+void FSPanelFace::onCommitTexture(const LLUICtrl* ctrl, const LLSD& data)
+{
+ LL_WARNS() << "onCommitTexture" << LL_ENDL;
+ add(LLStatViewer::EDIT_TEXTURE, 1);
+
+ LLSelectMgr::getInstance()->saveSelectedObjectTextures();
+ sendTexture();
+
+ LLGLenum image_format;
+ bool identical_image_format = false;
+ LLSelectedTE::getImageFormat(image_format, identical_image_format);
+
+ U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+ switch (image_format)
+ {
+ case GL_RGBA:
+ case GL_ALPHA:
+ {
+ alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+ }
+ break;
+
+ case GL_RGB: break;
+ default:
+ {
+ LL_WARNS() << "Unexpected tex format in FSPanelFace...resorting to no alpha" << LL_ENDL;
+ }
+ break;
+ }
+
+ mComboAlphaMode->selectNthItem(alpha_mode);
+
+ LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode());
+
+ // can't just pass "ctrl" on because it's const, and we also need to check
+ // the ctrl type so we make sure it's a texture swatch
+ onTextureSelectionChanged(ctrl->getName());
+}
+
+void FSPanelFace::onCommitNormalTexture(const LLUICtrl* ctrl, const LLSD& data)
+{
+ LL_DEBUGS("Materials") << data << LL_ENDL;
+ LLUUID nmap_id = getCurrentNormalMap();
+ sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE);
+ onTextureSelectionChanged(ctrl->getName());
+}
+
+void FSPanelFace::onCommitSpecularTexture(const LLUICtrl* ctrl, const LLSD& data)
+{
+ LL_DEBUGS("Materials") << data << LL_ENDL;
+ sendShiny(SHINY_TEXTURE);
+ onTextureSelectionChanged(ctrl->getName());
+}
+
+void FSPanelFace::onCloseTexturePicker(const LLSD& data)
+{
+ LL_DEBUGS("Materials") << data << LL_ENDL;
+ updateUI();
+}
+
+void FSPanelFace::onCancelTexture()
+{
+ LL_WARNS() << "onCancelTexture" << LL_ENDL;
+ LLSelectMgr::getInstance()->selectionRevertTextures();
+}
+
+void FSPanelFace::onCancelNormalTexture()
+{
+ U8 bumpy = 0;
+ bool identical_bumpy = false;
+ LLSelectedTE::getBumpmap(bumpy, identical_bumpy);
+ LLUUID normal_map_id = mBumpyTextureCtrl->getImageAssetID();
+ bumpy = normal_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
+ sendBump(bumpy);
+}
+
+void FSPanelFace::onCancelSpecularTexture()
+{
+ U8 shiny = 0;
+ bool identical_shiny = false;
+ LLSelectedTE::getShiny(shiny, identical_shiny);
+ LLUUID spec_map_id = mShinyTextureCtrl->getImageAssetID();
+ shiny = spec_map_id.isNull() ? shiny : SHINY_TEXTURE;
+ sendShiny(shiny);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// called when a user wants to edit existing media settings on a prim or prim face
+// TODO: test if there is media on the item and only allow editing if present
+// NOTE: there is no actual "Button" Edit Media, but this function is called from
+// onClickBtnAddMedia() where needed, so the naming is probably just old cruft -Zi
+void FSPanelFace::onClickBtnEditMedia()
+{
+ refreshMedia();
+ LLFloaterReg::showInstance("media_settings");
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// called when a user wants to delete media from a prim or prim face
+void FSPanelFace::onClickBtnDeleteMedia()
+{
+ LLNotificationsUtil::add("DeleteMedia", LLSD(), LLSD(), boost::bind(&FSPanelFace::deleteMediaConfirm, this, _1, _2));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// called when a user wants to add media to a prim or prim face
+void FSPanelFace::onClickBtnAddMedia()
+{
+ // check if multiple faces are selected
+ if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())
+ {
+ refreshMedia();
+ LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), boost::bind(&FSPanelFace::multipleFacesSelectedConfirm, this, _1, _2));
+ }
+ else
+ {
+ onClickBtnEditMedia();
+ }
+}
+
+bool FSPanelFace::deleteMediaConfirm(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch (option)
+ {
+ case 0: // "Yes"
+ LLSelectMgr::getInstance()->selectionSetMedia(0, LLSD());
+ if (LLFloaterReg::instanceVisible("media_settings"))
+ {
+ LLFloaterReg::hideInstance("media_settings");
+ }
+ break;
+
+ case 1: // "No"
+ default:
+ break;
+ }
+ return false;
+}
+
+bool FSPanelFace::multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch (option)
+ {
+ case 0: // "Yes"
+ LLFloaterReg::showInstance("media_settings");
+ break;
+
+ case 1: // "No"
+ default:
+ break;
+ }
+ return false;
+}
+
+//static
+void FSPanelFace::syncOffsetX(FSPanelFace* self, F32 offsetU)
+{
+ LLSelectedTEMaterial::setNormalOffsetX(self,offsetU);
+ LLSelectedTEMaterial::setSpecularOffsetX(self,offsetU);
+ self->mCtrlTexOffsetU->forceSetValue(offsetU);
+ self->sendTextureInfo();
+}
+
+//static
+void FSPanelFace::syncOffsetY(FSPanelFace* self, F32 offsetV)
+{
+ LLSelectedTEMaterial::setNormalOffsetY(self,offsetV);
+ LLSelectedTEMaterial::setSpecularOffsetY(self,offsetV);
+ self->mCtrlTexOffsetV->forceSetValue(offsetV);
+ self->sendTextureInfo();
+}
+
+void FSPanelFace::onCommitMaterialBumpyOffsetX()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncOffsetX(this, getCurrentBumpyOffsetU());
+ }
+ else
+ {
+ LLSelectedTEMaterial::setNormalOffsetX(this, getCurrentBumpyOffsetU());
+ }
+}
+
+void FSPanelFace::onCommitMaterialBumpyOffsetY()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncOffsetY(this, getCurrentBumpyOffsetV());
+ }
+ else
+ {
+ LLSelectedTEMaterial::setNormalOffsetY(this, getCurrentBumpyOffsetV());
+ }
+}
+
+void FSPanelFace::onCommitMaterialShinyOffsetX()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncOffsetX(this, getCurrentShinyOffsetU());
+ }
+ else
+ {
+ LLSelectedTEMaterial::setSpecularOffsetX(this, getCurrentShinyOffsetU());
+ }
+}
+
+void FSPanelFace::onCommitMaterialShinyOffsetY()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncOffsetY(this, getCurrentShinyOffsetV());
+ }
+ else
+ {
+ LLSelectedTEMaterial::setSpecularOffsetY(this, getCurrentShinyOffsetV());
+ }
+}
+
+//static
+void FSPanelFace::syncRepeatX(FSPanelFace* self, F32 scaleU)
+{
+ LLSelectedTEMaterial::setNormalRepeatX(self,scaleU);
+ LLSelectedTEMaterial::setSpecularRepeatX(self,scaleU);
+ self->sendTextureInfo();
+}
+
+//static
+void FSPanelFace::syncRepeatY(FSPanelFace* self, F32 scaleV)
+{
+ LLSelectedTEMaterial::setNormalRepeatY(self,scaleV);
+ LLSelectedTEMaterial::setSpecularRepeatY(self,scaleV);
+ self->sendTextureInfo();
+}
+
+void FSPanelFace::onCommitMaterialBumpyScaleX()
+{
+ F32 bumpy_scale_u = getCurrentBumpyScaleU();
+ if (isIdenticalPlanarTexgen())
+ {
+ bumpy_scale_u *= 0.5f;
+ }
+
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ mCtrlTexScaleU->forceSetValue(getCurrentBumpyScaleU());
+ syncRepeatX(this, bumpy_scale_u);
+ }
+ else
+ {
+ LLSelectedTEMaterial::setNormalRepeatX(this, bumpy_scale_u);
+ }
+}
+
+void FSPanelFace::onCommitMaterialBumpyScaleY()
+{
+ F32 bumpy_scale_v = getCurrentBumpyScaleV();
+ if (isIdenticalPlanarTexgen())
+ {
+ bumpy_scale_v *= 0.5f;
+ }
+
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ mCtrlTexScaleV->forceSetValue(getCurrentBumpyScaleV());
+ syncRepeatY(this, bumpy_scale_v);
+ }
+ else
+ {
+ LLSelectedTEMaterial::setNormalRepeatY(this, bumpy_scale_v);
+ }
+}
+
+void FSPanelFace::onCommitMaterialShinyScaleX()
+{
+ F32 shiny_scale_u = getCurrentShinyScaleU();
+ if (isIdenticalPlanarTexgen())
+ {
+ shiny_scale_u *= 0.5f;
+ }
+
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ mCtrlTexScaleU->forceSetValue(getCurrentShinyScaleU());
+ syncRepeatX(this, shiny_scale_u);
+ }
+ else
+ {
+ LLSelectedTEMaterial::setSpecularRepeatX(this, shiny_scale_u);
+ }
+}
+
+void FSPanelFace::onCommitMaterialShinyScaleY()
+{
+ F32 shiny_scale_v = getCurrentShinyScaleV();
+ if (isIdenticalPlanarTexgen())
+ {
+ shiny_scale_v *= 0.5f;
+ }
+
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ mCtrlTexScaleV->forceSetValue(getCurrentShinyScaleV());
+ syncRepeatY(this, shiny_scale_v);
+ }
+ else
+ {
+ LLSelectedTEMaterial::setSpecularRepeatY(this, shiny_scale_v);
+ }
+}
+
+//static
+void FSPanelFace::syncMaterialRot(FSPanelFace* self, F32 rot, int te)
+{
+ LLSelectedTEMaterial::setNormalRotation(self,rot * DEG_TO_RAD, te);
+ LLSelectedTEMaterial::setSpecularRotation(self,rot * DEG_TO_RAD, te);
+ self->sendTextureInfo();
+}
+
+void FSPanelFace::onCommitMaterialBumpyRot()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ mCtrlTexRot->forceSetValue(getCurrentBumpyRot());
+ syncMaterialRot(this, getCurrentBumpyRot());
+ }
+ else
+ {
+ if (mCheckPlanarAlign->getValue().asBoolean())
+ {
+ LLFace* last_face = NULL;
+ bool identical_face = false;
+ LLSelectedTE::getFace(last_face, identical_face);
+ FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+ }
+ else
+ {
+ LLSelectedTEMaterial::setNormalRotation(this, getCurrentBumpyRot() * DEG_TO_RAD);
+ }
+ }
+}
+
+void FSPanelFace::onCommitMaterialShinyRot()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ mCtrlTexRot->forceSetValue(getCurrentShinyRot());
+ syncMaterialRot(this, getCurrentShinyRot());
+ }
+ else
+ {
+ if (mCheckPlanarAlign->getValue().asBoolean())
+ {
+ LLFace* last_face = NULL;
+ bool identical_face = false;
+ LLSelectedTE::getFace(last_face, identical_face);
+ FSPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+ }
+ else
+ {
+ LLSelectedTEMaterial::setSpecularRotation(this, getCurrentShinyRot() * DEG_TO_RAD);
+ }
+ }
+}
+
+void FSPanelFace::onCommitMaterialGloss()
+{
+ LLSelectedTEMaterial::setSpecularLightExponent(this, getCurrentGlossiness());
+}
+
+void FSPanelFace::onCommitMaterialEnv()
+{
+ LLSelectedTEMaterial::setEnvironmentIntensity(this, getCurrentEnvIntensity());
+}
+
+void FSPanelFace::onCommitMaterialMaskCutoff()
+{
+ LLSelectedTEMaterial::setAlphaMaskCutoff(this, getCurrentAlphaMaskCutoff());
+}
+
+void FSPanelFace::onCommitTextureScaleX()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ F32 bumpy_scale_u = mCtrlTexScaleU->getValue().asReal();
+ if (isIdenticalPlanarTexgen())
+ {
+ bumpy_scale_u *= 0.5f;
+ }
+ syncRepeatX(this, bumpy_scale_u);
+ }
+ else
+ {
+ sendTextureInfo();
+ }
+ updateUI(true);
+}
+
+void FSPanelFace::onCommitTextureScaleY()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ F32 bumpy_scale_v = mCtrlTexScaleV->getValue().asReal();
+ if (isIdenticalPlanarTexgen())
+ {
+ bumpy_scale_v *= 0.5f;
+ }
+ syncRepeatY(this, bumpy_scale_v);
+ }
+ else
+ {
+ sendTextureInfo();
+ }
+ updateUI(true);
+}
+
+void FSPanelFace::onCommitTextureRot()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncMaterialRot(this, mCtrlTexRot->getValue().asReal());
+ }
+ else
+ {
+ sendTextureInfo();
+ }
+ updateUI(true);
+}
+
+
+void FSPanelFace::onCommitTextureOffsetX()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncOffsetX(this, mCtrlTexOffsetU->getValue().asReal());
+ }
+ else
+ {
+ sendTextureInfo();
+ }
+ updateUI(true);
+}
+
+void FSPanelFace::onCommitTextureOffsetY()
+{
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ syncOffsetY(this, mCtrlTexOffsetV->getValue().asReal());
+ }
+ else
+ {
+ sendTextureInfo();
+ }
+ updateUI(true);
+}
+
+// Commit the number of repeats per meter
+void FSPanelFace::onCommitRepeatsPerMeter()
+{
+ S32 materials_media = getCurrentMaterialType();
+ S32 material_type = 0;
+ // TODO: check if repeats per meter is even used for PBR -Zi
+ if (materials_media == MATMEDIA_PBR)
+ {
+ material_type = getCurrentPBRChannel();
+ }
+
+ if (materials_media == MATMEDIA_MATERIAL)
+ {
+ material_type = getCurrentMatChannel();
+ }
+
+ F32 repeats_per_meter = mCtrlRpt->getValue().asReal();
+
+ F32 obj_scale_s = 1.0f;
+ F32 obj_scale_t = 1.0f;
+
+ bool identical_scale_s = false;
+ bool identical_scale_t = false;
+
+ LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s);
+ LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t);
+
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
+
+ mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
+ mCtrlBumpyScaleV->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);
+
+ mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter);
+ mCtrlShinyScaleV->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);
+ }
+ else
+ {
+ switch (material_type)
+ {
+ case MATTYPE_DIFFUSE:
+ {
+ LLSelectMgr::getInstance()->selectionTexScaleAutofit(repeats_per_meter);
+ }
+ break;
+
+ case MATTYPE_NORMAL:
+ {
+ mCtrlBumpyScaleU->setValue(obj_scale_s * repeats_per_meter);
+ mCtrlBumpyScaleV->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);
+ }
+ break;
+
+ case MATTYPE_SPECULAR:
+ {
+ mCtrlShinyScaleU->setValue(obj_scale_s * repeats_per_meter);
+ mCtrlShinyScaleV->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);
+ }
+ break;
+
+ default:
+ llassert(false);
+ break;
+ }
+ }
+
+ // vertical scale and repeats per meter depends on each other, so force set on changes
+ updateUI(true);
+}
+
+struct FSPanelFaceSetMediaFunctor : public LLSelectedTEFunctor
+{
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ viewer_media_t pMediaImpl;
+
+ const LLTextureEntry &tep = object->getTEref(te);
+ const LLMediaEntry* mep = tep.hasMedia() ? tep.getMediaData() : NULL;
+ if (mep)
+ {
+ pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(mep->getMediaID());
+ }
+
+ if (pMediaImpl.isNull())
+ {
+ // If we didn't find face media for this face, check whether this face is showing parcel media.
+ pMediaImpl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep.getID());
+ }
+
+ if (pMediaImpl.notNull())
+ {
+ LLPluginClassMedia *media = pMediaImpl->getMediaPlugin();
+ if(media)
+ {
+ S32 media_width = media->getWidth();
+ S32 media_height = media->getHeight();
+ S32 texture_width = media->getTextureWidth();
+ S32 texture_height = media->getTextureHeight();
+ F32 scale_s = (F32)media_width / (F32)texture_width;
+ F32 scale_t = (F32)media_height / (F32)texture_height;
+
+ // set scale and adjust offset
+ object->setTEScaleS( te, scale_s );
+ object->setTEScaleT( te, scale_t ); // don't need to flip Y anymore since QT does this for us now.
+ object->setTEOffsetS( te, -( 1.0f - scale_s ) / 2.0f );
+ object->setTEOffsetT( te, -( 1.0f - scale_t ) / 2.0f );
+ }
+ }
+ return true;
+ };
+};
+
+void FSPanelFace::onClickAutoFix()
+{
+ FSPanelFaceSetMediaFunctor setfunc;
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
+
+ FSPanelFaceSendFunctor sendfunc;
+ LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc);
+}
+
+void FSPanelFace::onAlignTexture()
+{
+ alignTextureLayer();
+}
+
+void FSPanelFace::onClickBtnSavePBR()
+{
+ LLMaterialEditor::saveObjectsMaterialAs();
+}
+
+enum EPasteMode
+{
+ PASTE_COLOR,
+ PASTE_TEXTURE
+};
+
+struct FSPanelFacePasteTexFunctor : public LLSelectedTEFunctor
+{
+ public:
+ FSPanelFacePasteTexFunctor(FSPanelFace* panel, EPasteMode mode) :
+ mPanelFace(panel),
+ mMode(mode)
+ {
+ }
+
+ virtual bool apply(LLViewerObject* objectp, S32 te)
+ {
+ switch(mMode)
+ {
+ case PASTE_COLOR:
+ mPanelFace->onPasteColor(objectp, te);
+ break;
+
+ case PASTE_TEXTURE:
+ mPanelFace->onPasteTexture(objectp, te);
+ break;
+ }
+ return true;
+ }
+
+ private:
+ FSPanelFace *mPanelFace;
+ EPasteMode mMode;
+};
+
+struct FSPanelFaceUpdateFunctor : public LLSelectedObjectFunctor
+{
+ public:
+ FSPanelFaceUpdateFunctor(bool update_media) :
+ mUpdateMedia(update_media)
+ {
+ }
+
+ virtual bool apply(LLViewerObject* object)
+ {
+ object->sendTEUpdate();
+
+ if (mUpdateMedia)
+ {
+ LLVOVolume *vo = dynamic_cast(object);
+ if (vo && vo->hasMedia())
+ {
+ vo->sendMediaDataUpdate();
+ }
+ }
+ return true;
+ }
+
+ private:
+ bool mUpdateMedia;
+};
+
+struct FSPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor
+{
+ virtual bool apply(LLViewerObject* objectp, S32 te)
+ {
+ if (objectp && objectp->getTE(te))
+ {
+ LLTextureEntry* tep = objectp->getTE(te);
+ const LLMediaEntry *media_data = tep->getMediaData();
+ if (media_data)
+ {
+ if (media_data->getCurrentURL().empty() && media_data->getAutoPlay())
+ {
+ viewer_media_t media_impl =
+ LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID());
+ if (media_impl)
+ {
+ media_impl->navigateHome();
+ }
+ }
+ }
+ }
+ return true;
+ }
+};
+
+void FSPanelFace::onCopyColor()
+{
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+
+ if (!objectp || !node
+ || objectp->getPCode() != LL_PCODE_VOLUME
+ || !objectp->permModify()
+ || objectp->isPermanentEnforced()
+ || selected_count > 1)
+ {
+ return;
+ }
+
+ if (mClipboardParams.has("color"))
+ {
+ mClipboardParams["color"].clear();
+ }
+ else
+ {
+ mClipboardParams["color"] = LLSD::emptyArray();
+ }
+
+ std::map asset_item_map;
+
+ // a way to resolve situations where source and target have different amount of faces
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+ mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool());
+ for (S32 te = 0; te < num_tes; ++te)
+ {
+ if (node->isTESelected(te))
+ {
+ LLTextureEntry* tep = objectp->getTE(te);
+ if (tep)
+ {
+ LLSD te_data;
+
+ // asLLSD() includes media
+ te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow
+
+ mClipboardParams["color"].append(te_data);
+ }
+ }
+ }
+}
+
+void FSPanelFace::onPasteColor()
+{
+ if (!mClipboardParams.has("color"))
+ {
+ return;
+ }
+
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+
+ if (!objectp || !node
+ || objectp->getPCode() != LL_PCODE_VOLUME
+ || !objectp->permModify()
+ || objectp->isPermanentEnforced()
+ || selected_count > 1)
+ {
+ // not supposed to happen
+ LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL;
+ return;
+ }
+
+ bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+ LLSD &clipboard = mClipboardParams["color"]; // array
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+ S32 compare_tes = num_tes;
+
+ if (face_selection_mode)
+ {
+ compare_tes = 0;
+ for (S32 te = 0; te < num_tes; ++te)
+ {
+ if (node->isTESelected(te))
+ {
+ compare_tes++;
+ }
+ }
+ }
+
+ // we can copy if single face was copied in edit face mode or if face count matches
+ if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean())
+ && compare_tes != clipboard.size())
+ {
+ LLSD notif_args;
+ if (face_selection_mode)
+ {
+ static std::string reason = getString("paste_error_face_selection_mismatch");
+ notif_args["REASON"] = reason;
+ }
+ else
+ {
+ static std::string reason = getString("paste_error_object_face_count_mismatch");
+ notif_args["REASON"] = reason;
+ }
+ LLNotificationsUtil::add("FacePasteFailed", notif_args);
+ return;
+ }
+
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+ FSPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR);
+ selected_objects->applyToTEs(&paste_func);
+
+ FSPanelFaceUpdateFunctor sendfunc(false);
+ selected_objects->applyToObjects(&sendfunc);
+}
+
+void FSPanelFace::onPasteColor(LLViewerObject* objectp, S32 te)
+{
+ LLSD te_data;
+ LLSD &clipboard = mClipboardParams["color"]; // array
+ if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean())
+ {
+ te_data = *(clipboard.beginArray());
+ }
+ else if (clipboard[te])
+ {
+ te_data = clipboard[te];
+ }
+ else
+ {
+ return;
+ }
+
+ LLTextureEntry* tep = objectp->getTE(te);
+ if (tep)
+ {
+ if (te_data.has("te"))
+ {
+ // Color / Alpha
+ if (te_data["te"].has("colors"))
+ {
+ LLColor4 color = tep->getColor();
+
+ LLColor4 clip_color;
+ clip_color.setValue(te_data["te"]["colors"]);
+
+ // Color
+ color.mV[VRED] = clip_color.mV[VRED];
+ color.mV[VGREEN] = clip_color.mV[VGREEN];
+ color.mV[VBLUE] = clip_color.mV[VBLUE];
+
+ // Alpha
+ color.mV[VALPHA] = clip_color.mV[VALPHA];
+
+ objectp->setTEColor(te, color);
+ }
+
+ // Color/fullbright
+ if (te_data["te"].has("fullbright"))
+ {
+ objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger());
+ }
+
+ // Glow
+ if (te_data["te"].has("glow"))
+ {
+ objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal());
+ }
+ }
+ }
+}
+
+void FSPanelFace::onCopyTexture()
+{
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+
+ if (!objectp || !node
+ || objectp->getPCode() != LL_PCODE_VOLUME
+ || !objectp->permModify()
+ || objectp->isPermanentEnforced()
+ || selected_count > 1
+ || !LLMaterialEditor::canClipboardObjectsMaterial())
+ {
+ return;
+ }
+
+ if (mClipboardParams.has("texture"))
+ {
+ mClipboardParams["texture"].clear();
+ }
+ else
+ {
+ mClipboardParams["texture"] = LLSD::emptyArray();
+ }
+
+ std::map asset_item_map;
+
+ // a way to resolve situations where source and target have different amount of faces
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), objectp->getNumFaces());
+ mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool());
+ for (S32 te = 0; te < num_tes; ++te)
+ {
+ if (node->isTESelected(te))
+ {
+ LLTextureEntry* tep = objectp->getTE(te);
+ if (tep)
+ {
+ LLSD te_data;
+
+ // asLLSD() includes media
+ te_data["te"] = tep->asLLSD();
+ te_data["te"]["shiny"] = tep->getShiny();
+ te_data["te"]["bumpmap"] = tep->getBumpmap();
+ 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);
+ if (tep->getGLTFMaterialOverride() != nullptr)
+ {
+ te_data["te"]["pbr_override"] = tep->getGLTFMaterialOverride()->asJSON();
+ }
+
+ if (te_data["te"].has("imageid"))
+ {
+ LLUUID item_id;
+ LLUUID id = te_data["te"]["imageid"].asUUID();
+ bool from_library = get_is_predefined_texture(id);
+ bool full_perm = from_library;
+
+ if (!full_perm
+ && objectp->permCopy()
+ && objectp->permTransfer()
+ && objectp->permModify())
+ {
+ // If agent created this object and nothing is limiting permissions, mark as full perm
+ // If agent was granted permission to edit objects owned and created by somebody else, mark full perm
+ // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive
+ std::string creator_app_link;
+ LLUUID creator_id;
+ LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link);
+ full_perm = objectp->mOwnerID == creator_id;
+ }
+
+ if (id.notNull() && !full_perm)
+ {
+ std::map::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 highly 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;
+ }
+
+ // TODO: why scope this? -Zi
+ {
+ 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())
+ {
+ LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
+ if (itemp)
+ {
+ LLPermissions item_permissions = itemp->getPermissions();
+ if (item_permissions.allowOperationBy(PERM_COPY,
+ gAgent.getID(),
+ gAgent.getGroupID()))
+ {
+ te_data["te"]["imageitemid"] = item_id;
+ te_data["te"]["itemfullperm"] = itemp->getIsFullPerm();
+ if (!itemp->isFinished())
+ {
+ // needed for dropTextureAllFaces
+ LLInventoryModelBackgroundFetch::instance().start(item_id, false);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LLMaterialPtr material_ptr = tep->getMaterialParams();
+ if (!material_ptr.isNull())
+ {
+ LLSD mat_data;
+
+ mat_data["NormMap"] = material_ptr->getNormalID();
+ mat_data["SpecMap"] = material_ptr->getSpecularID();
+
+ mat_data["NormRepX"] = material_ptr->getNormalRepeatX();
+ mat_data["NormRepY"] = material_ptr->getNormalRepeatY();
+ mat_data["NormOffX"] = material_ptr->getNormalOffsetX();
+ mat_data["NormOffY"] = material_ptr->getNormalOffsetY();
+ mat_data["NormRot"] = material_ptr->getNormalRotation();
+
+ mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX();
+ mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY();
+ mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX();
+ mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY();
+ mat_data["SpecRot"] = material_ptr->getSpecularRotation();
+
+ mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue();
+ mat_data["SpecExp"] = material_ptr->getSpecularLightExponent();
+ mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity();
+ mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff();
+ mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode();
+
+ // Replace no-copy textures, destination texture will get used instead if available
+ if (mat_data.has("NormMap"))
+ {
+ LLUUID id = mat_data["NormMap"].asUUID();
+ if (id.notNull() && !get_can_copy_texture(id))
+ {
+ mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+ mat_data["NormMapNoCopy"] = true;
+ }
+ }
+ if (mat_data.has("SpecMap"))
+ {
+ LLUUID id = mat_data["SpecMap"].asUUID();
+ if (id.notNull() && !get_can_copy_texture(id))
+ {
+ mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture"));
+ mat_data["SpecMapNoCopy"] = true;
+ }
+ }
+
+ te_data["material"] = mat_data;
+ }
+
+ mClipboardParams["texture"].append(te_data);
+ }
+ }
+ }
+}
+
+void FSPanelFace::onPasteTexture()
+{
+ if (!mClipboardParams.has("texture"))
+ {
+ return;
+ }
+
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+
+ if (!objectp || !node
+ || objectp->getPCode() != LL_PCODE_VOLUME
+ || !objectp->permModify()
+ || objectp->isPermanentEnforced()
+ || selected_count > 1
+ || !LLMaterialEditor::canClipboardObjectsMaterial())
+ {
+ // not supposed to happen
+ LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL;
+ return;
+ }
+
+ bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
+ LLSD &clipboard = mClipboardParams["texture"]; // array
+ S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces());
+ S32 compare_tes = num_tes;
+
+ if (face_selection_mode)
+ {
+ compare_tes = 0;
+ for (S32 te = 0; te < num_tes; ++te)
+ {
+ if (node->isTESelected(te))
+ {
+ compare_tes++;
+ }
+ }
+ }
+
+ // we can copy if single face was copied in edit face mode or if face count matches
+ if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean())
+ && compare_tes != clipboard.size())
+ {
+ LLSD notif_args;
+ if (face_selection_mode)
+ {
+ static std::string reason = getString("paste_error_face_selection_mismatch");
+ notif_args["REASON"] = reason;
+ }
+ else
+ {
+ static std::string reason = getString("paste_error_object_face_count_mismatch");
+ notif_args["REASON"] = reason;
+ }
+
+ LLNotificationsUtil::add("FacePasteFailed", notif_args);
+ return;
+ }
+
+ bool full_perm_object = true;
+
+ LLSD::array_const_iterator iter = clipboard.beginArray();
+ LLSD::array_const_iterator end = clipboard.endArray();
+
+ for (; iter != end; ++iter)
+ {
+ const LLSD& te_data = *iter;
+ if (te_data.has("te") && te_data["te"].has("imageid"))
+ {
+ 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("imageitemid"))
+ {
+ LLUUID item_id = te_data["te"]["imageitemid"].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;
+ }
+ }
+ }
+ 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;
+ }
+ }
+ }
+ }
+
+ if (!full_perm_object)
+ {
+ LLNotificationsUtil::add("FacePasteTexturePermissions");
+ }
+
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+ FSPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE);
+ selected_objects->applyToTEs(&paste_func);
+
+ FSPanelFaceUpdateFunctor sendfunc(true);
+ selected_objects->applyToObjects(&sendfunc);
+
+ LLGLTFMaterialList::flushUpdates();
+
+ FSPanelFaceNavigateHomeFunctor navigate_home_func;
+ selected_objects->applyToTEs(&navigate_home_func);
+}
+
+void FSPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te)
+{
+ LLSD te_data;
+ LLSD &clipboard = mClipboardParams["texture"]; // array
+ if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean())
+ {
+ te_data = *(clipboard.beginArray());
+ }
+ else if (clipboard[te])
+ {
+ te_data = clipboard[te];
+ }
+ else
+ {
+ return;
+ }
+
+ LLTextureEntry* tep = objectp->getTE(te);
+ if (tep)
+ {
+ 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"))
+ {
+ const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id
+ LLViewerInventoryItem* 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 happen, 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 FSPanelFace::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 performance 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
+ }
+ }
+ }
+ }
+
+ if (itemp_res)
+ {
+ if (te == -1) // all faces
+ {
+ LLToolDragAndDrop::dropTextureAllFaces(objectp,
+ itemp_res,
+ from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+ LLUUID::null,
+ false);
+ }
+ else // one face
+ {
+ LLToolDragAndDrop::dropTextureOneFace(objectp,
+ te,
+ itemp_res,
+ from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
+ LLUUID::null,
+ false,
+ 0);
+ }
+ }
+ // not an inventory item or no complete items
+ else if (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);
+ objectp->setTEImage(U8(te), image);
+ }
+ }
+
+ if (te_data["te"].has("bumpmap"))
+ {
+ objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger());
+ }
+ if (te_data["te"].has("bumpshiny"))
+ {
+ objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger());
+ }
+ if (te_data["te"].has("bumpfullbright"))
+ {
+ objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger());
+ }
+ if (te_data["te"].has("texgen"))
+ {
+ objectp->setTETexGen(te, (U8)te_data["te"]["texgen"].asInteger());
+ }
+
+ // 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);
+
+ LLSD override_data;
+ override_data["object_id"] = objectp->getID();
+ override_data["side"] = te;
+ if (te_data["te"].has("pbr_override"))
+ {
+ override_data["gltf_json"] = te_data["te"]["pbr_override"];
+ }
+ else
+ {
+ override_data["gltf_json"] = "";
+ }
+
+ override_data["asset_id"] = te_data["te"]["pbr"].asUUID();
+
+ LLGLTFMaterialList::queueUpdate(override_data);
+ }
+ else
+ {
+ objectp->setRenderMaterialID(te, LLUUID::null, false /*send in bulk later*/ );
+ tep->setGLTFRenderMaterial(nullptr);
+ tep->setGLTFMaterialOverride(nullptr);
+
+ // blank out most override data on the server
+ LLGLTFMaterialList::queueApply(objectp, te, LLUUID::null);
+ }
+
+ // Texture map
+ if (te_data["te"].has("scales") && te_data["te"].has("scalet"))
+ {
+ objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal());
+ }
+ if (te_data["te"].has("offsets") && te_data["te"].has("offsett"))
+ {
+ objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal());
+ }
+ if (te_data["te"].has("imagerot"))
+ {
+ objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal());
+ }
+
+ // Media
+ if (te_data["te"].has("media_flags"))
+ {
+ U8 media_flags = te_data["te"]["media_flags"].asInteger();
+ objectp->setTEMediaFlags(te, media_flags);
+ LLVOVolume *vo = dynamic_cast(objectp);
+ if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY))
+ {
+ vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/);
+ }
+ }
+ else
+ {
+ // Keep media flags on destination unchanged
+ }
+ }
+
+ if (te_data.has("material"))
+ {
+ LLUUID object_id = objectp->getID();
+
+ // Normal
+ // Replace placeholders with target's
+ if (te_data["material"].has("NormMapNoCopy"))
+ {
+ LLMaterialPtr material = tep->getMaterialParams();
+ if (material.notNull())
+ {
+ LLUUID id = material->getNormalID();
+ if (id.notNull())
+ {
+ te_data["material"]["NormMap"] = id;
+ }
+ }
+ }
+
+ LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id);
+ LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id);
+
+ // Specular
+ // Replace placeholders with target's
+ if (te_data["material"].has("SpecMapNoCopy"))
+ {
+ LLMaterialPtr material = tep->getMaterialParams();
+ if (material.notNull())
+ {
+ LLUUID id = material->getSpecularID();
+ if (id.notNull())
+ {
+ te_data["material"]["SpecMap"] = id;
+ }
+ }
+ }
+
+ LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id);
+ LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id);
+ LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id);
+ LLColor4U spec_color(te_data["material"]["SpecColor"]);
+ LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te);
+ LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id);
+ LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id);
+ LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["DiffuseAlphaMode"].asInteger(), te, object_id);
+ LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["AlphaMaskCutoff"].asInteger(), te, object_id);
+
+ if (te_data.has("te") && te_data["te"].has("shiny"))
+ {
+ objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger());
+ }
+ }
+ }
+}
+
+void FSPanelFace::onCopyFaces()
+{
+ onCopyTexture();
+ onCopyColor();
+ mBtnPasteFaces->setEnabled(!mClipboardParams.emptyMap() && (mClipboardParams.has("color") || mClipboardParams.has("texture")));
+}
+
+void FSPanelFace::onPasteFaces()
+{
+ LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection();
+
+ FSPanelFacePasteTexFunctor paste_texture_func(this, PASTE_TEXTURE);
+ selected_objects->applyToTEs(&paste_texture_func);
+
+ FSPanelFacePasteTexFunctor paste_color_func(this, PASTE_COLOR);
+ selected_objects->applyToTEs(&paste_color_func);
+
+ FSPanelFaceUpdateFunctor sendfunc(true);
+ selected_objects->applyToObjects(&sendfunc);
+
+ FSPanelFaceNavigateHomeFunctor navigate_home_func;
+ selected_objects->applyToTEs(&navigate_home_func);
+}
+
+void FSPanelFace::onCommitPlanarAlign()
+{
+ getState();
+ sendTextureInfo();
+}
+
+void FSPanelFace::updateGLTFTextureTransform(float value, U32 pbr_channel, std::function edit)
+{
+ U32 texture_info_start;
+ U32 texture_info_end;
+
+ const LLGLTFMaterial::TextureInfo texture_info = mPBRChannelToTextureInfo[pbr_channel];
+ if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT)
+ {
+ texture_info_start = 0;
+ texture_info_end = LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT;
+ }
+ else
+ {
+ texture_info_start = mPBRChannelToTextureInfo[pbr_channel];
+ texture_info_end = texture_info_start + 1;
+ }
+
+ updateSelectedGLTFMaterials([&](LLGLTFMaterial* new_override)
+ {
+ for (U32 ti = texture_info_start; ti < texture_info_end; ++ti)
+ {
+ LLGLTFMaterial::TextureTransform& new_transform = new_override->mTextureTransform[(LLGLTFMaterial::TextureInfo)ti];
+ edit(&new_transform);
+ }
+ });
+}
+
+void FSPanelFace::setMaterialOverridesFromSelection()
+{
+ // TODO: move to .h -Zi
+ std::map spinner_suffixes =
+ {
+ { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_BASE_COLOR, "_Base" },
+ { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_NORMAL, "_Normal" },
+ { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, "_Metallic" },
+ { LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_EMISSIVE, "_Emissive" }
+ };
+
+ bool read_transform = true;
+ LLGLTFMaterial::TextureTransform transform;
+ bool scale_u_same = true;
+ bool scale_v_same = true;
+ bool rotation_same = true;
+ bool offset_u_same = true;
+ bool offset_v_same = true;
+
+ // Always iterate over the whole set of texture channels
+ for (U32 i = 0; i < LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT; ++i)
+ {
+ std::string spinner_suffix = spinner_suffixes[(LLGLTFMaterial::TextureInfo) i];
+
+ LLGLTFMaterial::TextureTransform this_transform;
+
+ bool this_scale_u_same = true;
+ bool this_scale_v_same = true;
+ bool this_rotation_same = true;
+ bool this_offset_u_same = true;
+ bool this_offset_v_same = true;
+
+ readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat)
+ {
+ return mat ? mat->mTextureTransform[i].mScale[VX] : 0.f;
+ }, this_transform.mScale[VX], this_scale_u_same, true, 1e-3f);
+
+ readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat)
+ {
+ return mat ? mat->mTextureTransform[i].mScale[VY] : 0.f;
+ }, this_transform.mScale[VY], this_scale_v_same, true, 1e-3f);
+
+ readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat)
+ {
+ return mat ? mat->mTextureTransform[i].mRotation : 0.f;
+ }, this_transform.mRotation, this_rotation_same, true, 1e-3f);
+
+ readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat)
+ {
+ return mat ? mat->mTextureTransform[i].mOffset[VX] : 0.f;
+ }, this_transform.mOffset[VX], this_offset_u_same, true, 1e-3f);
+
+ readSelectedGLTFMaterial([&](const LLGLTFMaterial* mat)
+ {
+ return mat ? mat->mTextureTransform[i].mOffset[VY] : 0.f;
+ }, this_transform.mOffset[VY], this_offset_v_same, true, 1e-3f);
+
+ scale_u_same = scale_u_same && this_scale_u_same;
+ scale_v_same = scale_v_same && this_scale_v_same;
+ rotation_same = rotation_same && this_rotation_same;
+ offset_u_same = offset_u_same && this_offset_u_same;
+ offset_v_same = offset_v_same && this_offset_v_same;
+
+ if (read_transform)
+ {
+ read_transform = false;
+ transform = this_transform;
+ }
+ else
+ {
+ scale_u_same = scale_u_same && (this_transform.mScale[VX] == transform.mScale[VX]);
+ scale_v_same = scale_v_same && (this_transform.mScale[VY] == transform.mScale[VY]);
+ rotation_same = rotation_same && (this_transform.mRotation == transform.mRotation);
+ offset_u_same = offset_u_same && (this_transform.mOffset[VX] == transform.mOffset[VX]);
+ offset_v_same = offset_v_same && (this_transform.mOffset[VY] == transform.mOffset[VY]);
+ }
+
+ LLUICtrl* gltfCtrlTextureScaleU = findChild("gltfTextureScaleU" + spinner_suffix);
+ LLUICtrl* gltfCtrlTextureScaleV = findChild("gltfTextureScaleV" + spinner_suffix);
+ LLUICtrl* gltfCtrlTextureRotation = findChild("gltfTextureRotation" + spinner_suffix);
+ LLUICtrl* gltfCtrlTextureOffsetU = findChild("gltfTextureOffsetU" + spinner_suffix);
+ LLUICtrl* gltfCtrlTextureOffsetV = findChild("gltfTextureOffsetV" + spinner_suffix);
+
+ gltfCtrlTextureScaleU->setValue(this_transform.mScale[VX]);
+ gltfCtrlTextureScaleV->setValue(this_transform.mScale[VY]);
+ gltfCtrlTextureRotation->setValue(this_transform.mRotation * RAD_TO_DEG);
+ gltfCtrlTextureOffsetU->setValue(this_transform.mOffset[VX]);
+ gltfCtrlTextureOffsetV->setValue(this_transform.mOffset[VY]);
+ }
+
+ LLUICtrl* gltfCtrlTextureScaleU = findChild("gltfTextureScaleU_All");
+ LLUICtrl* gltfCtrlTextureScaleV = findChild("gltfTextureScaleV_All");
+ LLUICtrl* gltfCtrlTextureRotation = findChild("gltfTextureRotation_All");
+ LLUICtrl* gltfCtrlTextureOffsetU = findChild("gltfTextureOffsetU_All");
+ LLUICtrl* gltfCtrlTextureOffsetV = findChild("gltfTextureOffsetV_All");
+
+ gltfCtrlTextureScaleU->setValue(transform.mScale[VX]);
+ gltfCtrlTextureScaleV->setValue(transform.mScale[VY]);
+ gltfCtrlTextureRotation->setValue(transform.mRotation * RAD_TO_DEG);
+ gltfCtrlTextureOffsetU->setValue(transform.mOffset[VX]);
+ gltfCtrlTextureOffsetV->setValue(transform.mOffset[VY]);
+
+ gltfCtrlTextureScaleU->setTentative(!scale_u_same);
+ gltfCtrlTextureScaleV->setTentative(!scale_v_same);
+ gltfCtrlTextureRotation->setTentative(!rotation_same);
+ gltfCtrlTextureOffsetU->setTentative(!offset_u_same);
+ gltfCtrlTextureOffsetV->setTentative(!offset_v_same);
+}
+
+void FSPanelFace::Selection::connect()
+{
+ if (!mSelectConnection.connected())
+ {
+ mSelectConnection = LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&FSPanelFace::Selection::onSelectionChanged, this));
+ }
+}
+
+bool FSPanelFace::Selection::update()
+{
+ const bool changed = mChanged || compareSelection();
+ mChanged = false;
+ return changed;
+}
+
+void FSPanelFace::Selection::onSelectedObjectUpdated(const LLUUID& object_id, S32 side)
+{
+ if (object_id == mSelectedObjectID)
+ {
+ if (side == mLastSelectedSide)
+ {
+ mChanged = true;
+ }
+ else if (mLastSelectedSide == -1) // if last selected face was deselected
+ {
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
+ if (node && node->isTESelected(side))
+ {
+ mChanged = true;
+ }
+ }
+ }
+}
+
+bool FSPanelFace::Selection::compareSelection()
+{
+ if (!mNeedsSelectionCheck)
+ {
+ return false;
+ }
+
+ mNeedsSelectionCheck = false;
+
+ const S32 old_object_count = mSelectedObjectCount;
+ const S32 old_te_count = mSelectedTECount;
+ const LLUUID old_object_id = mSelectedObjectID;
+ const S32 old_side = mLastSelectedSide;
+
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ LLSelectNode* node = selection->getFirstNode();
+ if (node)
+ {
+ LLViewerObject* object = node->getObject();
+ mSelectedObjectCount = selection->getObjectCount();
+ mSelectedTECount = selection->getTECount();
+ mSelectedObjectID = object->getID();
+ mLastSelectedSide = node->getLastSelectedTE();
+ }
+ else
+ {
+ mSelectedObjectCount = 0;
+ mSelectedTECount = 0;
+ mSelectedObjectID = LLUUID::null;
+ mLastSelectedSide = -1;
+ }
+
+ const bool selection_changed =
+ old_object_count != mSelectedObjectCount
+ || old_te_count != mSelectedTECount
+ || old_object_id != mSelectedObjectID
+ || old_side != mLastSelectedSide;
+
+ mChanged = mChanged || selection_changed;
+
+ return selection_changed;
+}
+
+void FSPanelFace::onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data)
+{
+ // TODO: put into .h -Zi
+ std::map types =
+ {
+ { "all", PBRTYPE_RENDER_MATERIAL_ID },
+ { "base", PBRTYPE_BASE_COLOR },
+ { "normal", PBRTYPE_NORMAL },
+ { "metallic", PBRTYPE_METALLIC_ROUGHNESS },
+ { "emissive", PBRTYPE_EMISSIVE }
+ };
+
+ std::string user_data_string = user_data.asString();
+
+ if (!types.count(user_data_string))
+ {
+ LL_WARNS() << "Unknown PBR channel " << user_data_string << LL_ENDL;
+ return;
+ }
+
+ const S32 pbr_channel = types[user_data.asString()];
+
+ const std::string& spinner_name = ctrl->getName();
+ const float value = ctrl->getValue().asReal();
+
+ if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleU"))
+ {
+ updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform)
+ {
+ new_transform->mScale.mV[VX] = value;
+ });
+ }
+ else if (LLStringUtil::startsWith(spinner_name, "gltfTextureScaleV"))
+ {
+ updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform)
+ {
+ new_transform->mScale.mV[VY] = value;
+ });
+ }
+ else if (LLStringUtil::startsWith(spinner_name, "gltfTextureRotation"))
+ {
+ updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform)
+ {
+ new_transform->mRotation = value * DEG_TO_RAD;
+ });
+ }
+ else if (LLStringUtil::startsWith(spinner_name, "gltfTextureOffsetU"))
+ {
+ updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform)
+ {
+ new_transform->mOffset.mV[VX] = value;
+ });
+ }
+ else if (LLStringUtil::startsWith(spinner_name, "gltfTextureOffsetV"))
+ {
+ updateGLTFTextureTransform(value, pbr_channel, [&](LLGLTFMaterial::TextureTransform* new_transform)
+ {
+ new_transform->mOffset.mV[VY] = value;
+ });
+ }
+}
+
+// selection inside the texture/material picker changed
+void FSPanelFace::onTextureSelectionChanged(const std::string& which_control)
+{
+ LL_DEBUGS("Materials") << "control " << which_control << LL_ENDL;
+
+ LLTextureCtrl* texture_ctrl = findChild(which_control);
+ if (texture_ctrl)
+ {
+ LLInventoryItem* itemp = gInventory.getItem(texture_ctrl->getImageItemID());
+ if (!itemp)
+ {
+ // no inventory asset available, i.e. could be "Blank"
+ return;
+ }
+
+ LL_WARNS("Materials") << "item inventory id " << itemp->getUUID() << " - item asset " << itemp->getAssetUUID() << LL_ENDL;
+
+ LLUUID obj_owner_id;
+ std::string obj_owner_name;
+ LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name);
+
+ LLSaleInfo sale_info;
+ LLSelectMgr::instance().selectGetSaleInfo(sale_info);
+
+ bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this texture?
+ bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this texture?
+ bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply texture belong to the agent?
+ bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply texture not for sale?
+
+ if (can_copy && can_transfer)
+ {
+ texture_ctrl->setCanApply(true, true);
+ return;
+ }
+
+ // if texture has (no-transfer) attribute it can be applied only for object which we own and is not for sale
+ texture_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale);
+
+ if (gSavedSettings.getBOOL("TextureLivePreview"))
+ {
+ LLNotificationsUtil::add("LivePreviewUnavailable");
+ }
+ }
+}
+
+// selection inside the texture/material picker changed
+void FSPanelFace::onPbrSelectionChanged(LLInventoryItem* itemp)
+{
+ LLUUID obj_owner_id;
+ std::string obj_owner_name;
+ LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name);
+
+ LLSaleInfo sale_info;
+ LLSelectMgr::instance().selectGetSaleInfo(sale_info);
+
+ bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this material?
+ bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this material?
+ bool can_modify = itemp->getPermissions().allowOperationBy(PERM_MODIFY, gAgentID); // do we have perm to transfer this material?
+ bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply material belong to the agent?
+ bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply material not for sale?
+
+ if (can_copy && can_transfer && can_modify)
+ {
+ mMaterialCtrlPBR->setCanApply(true, true);
+ return;
+ }
+
+ // if material has (no-transfer) attribute it can be applied only for object which we own and is not for sale
+ mMaterialCtrlPBR->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale);
+
+ if (gSavedSettings.getBOOL("TextureLivePreview"))
+ {
+ LLNotificationsUtil::add("LivePreviewUnavailablePBR");
+ }
+}
+
+bool FSPanelFace::isIdenticalPlanarTexgen()
+{
+ LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT;
+ bool identical_texgen = false;
+ LLSelectedTE::getTexGen(selected_texgen, identical_texgen);
+ return (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR));
+}
+
+void FSPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical_face)
+{
+ struct LLSelectedTEGetFace : public LLSelectedTEGetFunctor
+ {
+ LLFace* get(LLViewerObject* object, S32 te)
+ {
+ return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
+ }
+ } get_te_face_func;
+
+ identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr);
+}
+
+void FSPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)
+{
+ LLGLenum image_format{ GL_RGB };
+ struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor
+ {
+ LLGLenum get(LLViewerObject* object, S32 te_index)
+ {
+ LLViewerTexture* image = object->getTEImage(te_index);
+ return image ? image->getPrimaryFormat() : GL_RGB;
+ }
+ } get_glenum;
+
+ identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_glenum, image_format);
+ image_format_to_return = image_format;
+}
+
+void FSPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
+{
+ struct LLSelectedTEGetTexId : public LLSelectedTEGetFunctor
+ {
+ LLUUID get(LLViewerObject* object, S32 te_index)
+ {
+ LLTextureEntry *te = object->getTE(te_index);
+ if (te)
+ {
+ if ((te->getID() == IMG_USE_BAKED_EYES) || (te->getID() == IMG_USE_BAKED_HAIR) || (te->getID() == IMG_USE_BAKED_HEAD) || (te->getID() == IMG_USE_BAKED_LOWER) || (te->getID() == IMG_USE_BAKED_SKIRT) || (te->getID() == IMG_USE_BAKED_UPPER)
+ || (te->getID() == IMG_USE_BAKED_LEFTARM) || (te->getID() == IMG_USE_BAKED_LEFTLEG) || (te->getID() == IMG_USE_BAKED_AUX1) || (te->getID() == IMG_USE_BAKED_AUX2) || (te->getID() == IMG_USE_BAKED_AUX3))
+ {
+ return te->getID();
+ }
+ }
+
+ LLUUID id;
+ LLViewerTexture* image = object->getTEImage(te_index);
+ if (image)
+ {
+ id = image->getID();
+ }
+
+ if (!id.isNull() && LLViewerMedia::getInstance()->textureHasMedia(id))
+ {
+ if (te)
+ {
+ LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL;
+ if(!tex)
+ {
+ tex = LLViewerFetchedTexture::sDefaultImagep;
+ }
+ if (tex)
+ {
+ id = tex->getID();
+ }
+ }
+ }
+ return id;
+ }
+ } func;
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id );
+}
+
+void FSPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material)
+{
+ struct MaterialFunctor : public LLSelectedTEGetFunctor
+ {
+ LLMaterialPtr get(LLViewerObject* object, S32 te_index)
+ {
+ return object->getTEref(te_index).getMaterialParams();
+ }
+ } func;
+
+ identical_material = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_ptr);
+}
+
+void FSPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool& identical)
+{
+ struct LLSelectedTEGetMaxSpecRepeats : public LLSelectedTEGetFunctor
+ {
+ F32 get(LLViewerObject* object, S32 face)
+ {
+ LLMaterial* mat = object->getTEref(face).getMaterialParams().get();
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ F32 repeats_s = 1.0f;
+ F32 repeats_t = 1.0f;
+ if (mat)
+ {
+ mat->getSpecularRepeat(repeats_s, repeats_t);
+ repeats_s /= object->getScale().mV[s_axis];
+ repeats_t /= object->getScale().mV[t_axis];
+ }
+ return llmax(repeats_s, repeats_t);
+ }
+
+ } max_spec_repeats_func;
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_spec_repeats_func, repeats);
+}
+
+void FSPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool& identical)
+{
+ struct LLSelectedTEGetMaxNormRepeats : public LLSelectedTEGetFunctor
+ {
+ F32 get(LLViewerObject* object, S32 face)
+ {
+ LLMaterial* mat = object->getTEref(face).getMaterialParams().get();
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ F32 repeats_s = 1.0f;
+ F32 repeats_t = 1.0f;
+ if (mat)
+ {
+ mat->getNormalRepeat(repeats_s, repeats_t);
+ repeats_s /= object->getScale().mV[s_axis];
+ repeats_t /= object->getScale().mV[t_axis];
+ }
+ return llmax(repeats_s, repeats_t);
+ }
+
+ } max_norm_repeats_func;
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_norm_repeats_func, repeats);
+}
+
+void FSPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, const bool diffuse_texture_has_alpha)
+{
+ struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor
+ {
+ LLSelectedTEGetDiffuseAlphaMode() : _isAlpha(false) {}
+ LLSelectedTEGetDiffuseAlphaMode(bool diffuse_texture_has_alpha) : _isAlpha(diffuse_texture_has_alpha) {}
+ virtual ~LLSelectedTEGetDiffuseAlphaMode() {}
+
+ U8 get(LLViewerObject* object, S32 face)
+ {
+ U8 diffuse_mode = _isAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+ LLTextureEntry* tep = object->getTE(face);
+ if (tep)
+ {
+ LLMaterial* mat = tep->getMaterialParams().get();
+ if (mat)
+ {
+ diffuse_mode = mat->getDiffuseAlphaMode();
+ }
+ }
+
+ return diffuse_mode;
+ }
+
+ bool _isAlpha; // whether or not the diffuse texture selected contains alpha information
+ } get_diff_mode(diffuse_texture_has_alpha);
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
+}
+
+void FSPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical)
+{
+ struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor
+ {
+ F32 get(LLViewerObject* object, S32 face)
+ {
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+ return object->getScale().mV[s_axis];
+ }
+
+ } scale_s_func;
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_s_func, scale_s );
+}
+
+void FSPanelFace::LLSelectedTE::getObjectScaleT(F32& scale_t, bool& identical)
+{
+ struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor
+ {
+ F32 get(LLViewerObject* object, S32 face)
+ {
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+ return object->getScale().mV[t_axis];
+ }
+
+ } scale_t_func;
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_t_func, scale_t );
+}
+
+void FSPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identical)
+{
+ struct LLSelectedTEGetMaxDiffuseRepeats : public LLSelectedTEGetFunctor
+ {
+ F32 get(LLViewerObject* object, S32 face)
+ {
+ U32 s_axis = VX;
+ U32 t_axis = VY;
+ LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+ F32 repeats_s = object->getTEref(face).mScaleS / object->getScale().mV[s_axis];
+ F32 repeats_t = object->getTEref(face).mScaleT / object->getScale().mV[t_axis];
+ return llmax(repeats_s, repeats_t);
+ }
+
+ } max_diff_repeats_func;
+
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats );
+}
+
+void FSPanelFace::onClickMapsSync()
+{
+ getState();
+ if (gSavedSettings.getBOOL("SyncMaterialSettings"))
+ {
+ alignMaterialsProperties();
+ }
+}
+
+// used to be called from two places but onCommitFlip() now does it a different way
+// so we end up with this still being a function but strictly it could be moved
+// into onClickMapsSync() -Zi
+void FSPanelFace::alignMaterialsProperties()
+{
+ // FIRE-11911: Synchronize materials doesn't work with planar textures
+ // Don't even try to do the alignment if we wind up here and planar is enabled.
+ if (mCheckPlanarAlign->getValue().asBoolean())
+ {
+ return;
+ }
+ // FIRE-11911
+
+ F32 tex_scale_u = getCurrentTextureScaleU();
+ F32 tex_scale_v = getCurrentTextureScaleV();
+ F32 tex_offset_u = getCurrentTextureOffsetU();
+ F32 tex_offset_v = getCurrentTextureOffsetV();
+ F32 tex_rot = getCurrentTextureRot();
+
+ // FIRE-12275: Material offset not working correctly
+ // Since the server cannot store negative offsets for materials
+ // textures, we normalize them to equivalent positive values here.
+ tex_offset_u = (tex_offset_u < 0.0) ? 1.0 + tex_offset_u : tex_offset_u;
+ tex_offset_v = (tex_offset_v < 0.0) ? 1.0 + tex_offset_v : tex_offset_v;
+ // FIRE-12275
+
+ // FIRE-12831: Negative rotations revert to zero
+ // The same goes for rotations as for offsets.
+ tex_rot = (tex_rot < 0.0) ? 360.0 + tex_rot : tex_rot;
+ // FIRE-12831
+
+ mCtrlShinyScaleU->setValue(tex_scale_u);
+ mCtrlShinyScaleV->setValue(tex_scale_v);
+ mCtrlShinyOffsetU->setValue(tex_offset_u);
+ mCtrlShinyOffsetV->setValue(tex_offset_v);
+ mCtrlShinyRot->setValue(tex_rot);
+
+ // What is this abomination!? -Zi
+ LLSelectedTEMaterial::setSpecularRepeatX(this, tex_scale_u);
+ LLSelectedTEMaterial::setSpecularRepeatY(this, tex_scale_v);
+ LLSelectedTEMaterial::setSpecularOffsetX(this, tex_offset_u);
+ LLSelectedTEMaterial::setSpecularOffsetY(this, tex_offset_v);
+ LLSelectedTEMaterial::setSpecularRotation(this, tex_rot * DEG_TO_RAD);
+
+ mCtrlBumpyScaleU->setValue(tex_scale_u);
+ mCtrlBumpyScaleV->setValue(tex_scale_v);
+ mCtrlBumpyOffsetU->setValue(tex_offset_u);
+ mCtrlBumpyOffsetV->setValue(tex_offset_v);
+ mCtrlBumpyRot->setValue(tex_rot);
+
+ // What is this abomination!? -Zi
+ LLSelectedTEMaterial::setNormalRepeatX(this, tex_scale_u);
+ LLSelectedTEMaterial::setNormalRepeatY(this, tex_scale_v);
+ LLSelectedTEMaterial::setNormalOffsetX(this, tex_offset_u);
+ LLSelectedTEMaterial::setNormalOffsetY(this, tex_offset_v);
+ LLSelectedTEMaterial::setNormalRotation(this, tex_rot * DEG_TO_RAD);
+}
+
+void FSPanelFace::onCommitFlip(const LLSD& user_data)
+{
+ LL_WARNS() << "onCommitFlip" << LL_ENDL;
+ std::string control_name = user_data.asString();
+ if (control_name.empty())
+ {
+ LL_WARNS() << "empty user data!" << LL_ENDL;
+ return;
+ }
+
+ LL_WARNS() << "control name: " << control_name << LL_ENDL;
+
+ LLSpinCtrl* spinner = findChild(control_name);
+ if (spinner)
+ {
+ // TODO: compensate for normal/specular map doubling of values in planar mapping mode -Zi
+ F32 value = -(spinner->getValue().asReal());
+ spinner->setValue(value);
+ spinner->forceEditorCommit();
+ }
+ else
+ {
+ LL_WARNS() << "spinner not found: " << control_name << LL_ENDL;
+ }
+}
+
+void FSPanelFace::changePrecision(S32 decimal_precision)
+{
+ mCtrlTexScaleU->setPrecision(decimal_precision);
+ mCtrlTexScaleV->setPrecision(decimal_precision);
+ mCtrlBumpyScaleU->setPrecision(decimal_precision);
+ mCtrlBumpyScaleV->setPrecision(decimal_precision);
+ mCtrlShinyScaleU->setPrecision(decimal_precision);
+ mCtrlShinyScaleV->setPrecision(decimal_precision);
+ mCtrlTexOffsetU->setPrecision(decimal_precision);
+ mCtrlTexOffsetV->setPrecision(decimal_precision);
+ mCtrlBumpyOffsetU->setPrecision(decimal_precision);
+ mCtrlBumpyOffsetV->setPrecision(decimal_precision);
+ mCtrlShinyOffsetU->setPrecision(decimal_precision);
+ mCtrlShinyOffsetV->setPrecision(decimal_precision);
+ mCtrlTexRot->setPrecision(decimal_precision);
+ mCtrlBumpyRot->setPrecision(decimal_precision);
+ mCtrlShinyRot->setPrecision(decimal_precision);
+ mCtrlRpt->setPrecision(decimal_precision);
+ // TODO: add PBR spinners -Zi
+}
+
+void FSPanelFace::onShowFindAllButton(LLUICtrl* ctrl, const LLSD& user_data)
+{
+ findChildView(user_data.asStringRef())->setVisible(true);
+}
+
+void FSPanelFace::onHideFindAllButton(LLUICtrl* ctrl, const LLSD& user_data)
+{
+ findChildView(user_data.asStringRef())->setVisible(false);
+}
+
+// Find all faces with same texture
+void FSPanelFace::onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data)
+{
+ std::unordered_set objects;
+
+ // get a list of all linksets where at least one face is selected
+ for (auto iter = LLSelectMgr::getInstance()->getSelection()->valid_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
+ {
+ objects.insert((*iter)->getObject()->getRootEdit());
+ }
+
+ // clean out the selection
+ LLSelectMgr::getInstance()->deselectAll();
+
+ // select all faces of all linksets that were found before
+ LLObjectSelectionHandle handle;
+ for(auto objectp : objects)
+ {
+ handle = LLSelectMgr::getInstance()->selectObjectAndFamily(objectp, true, false);
+ }
+
+ // get the texture channel we are interested in - using the first letter is sufficient
+ // and makes things faster in the if () blocks
+ char channel = user_data.asStringRef()[0];
+
+ // grab the texture ID from the texture selector
+ LLTextureCtrl* texture_control = mTextureCtrl;
+ if (channel == 'n')
+ {
+ texture_control = mBumpyTextureCtrl;
+ }
+ else if (channel == 's')
+ {
+ texture_control = mShinyTextureCtrl;
+ }
+ else if (channel == 'g')
+ {
+ texture_control = mMaterialCtrlPBR;
+ }
+
+ LLUUID id = texture_control->getImageAssetID();
+
+ // go through all selected links in all selected linksets
+ for (auto iter = handle->begin(); iter != handle->end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* objectp = node->getObject();
+
+ U8 te_count = objectp->getNumTEs();
+
+ for (U8 i = 0; i < te_count; i++)
+ {
+ LLUUID image_id;
+ if (channel == 'd')
+ {
+ image_id = objectp->getTEImage(i)->getID();
+ }
+ else if (channel == 'g')
+ {
+ image_id = objectp->getRenderMaterialID(i);
+ }
+ else
+ {
+ const LLMaterialPtr mat = objectp->getTEref(i).getMaterialParams();
+ if (mat.notNull())
+ {
+ if (channel == 'n')
+ {
+ image_id = mat->getNormalID();
+ }
+ else if (channel == 's')
+ {
+ image_id = mat->getSpecularID();
+ }
+ }
+ }
+
+ // deselect all faces that use a different texture UUID
+ if (image_id != id)
+ {
+ objectp->setTESelected(i, false);
+ node->selectTE(i, false);
+ }
+ }
+ }
+}
+
+//
+// convenience functions around tab containers -Zi
+//
+
+S32 FSPanelFace::getCurrentMaterialType() const
+{
+ const std::string& tab_name = mTabsPBRMatMedia->getCurrentPanel()->getName();
+
+ if (tab_name == "panel_material_type_pbr")
+ {
+ return MATMEDIA_PBR;
+ }
+ else if (tab_name == "panel_material_type_media")
+ {
+ return MATMEDIA_MEDIA;
+ }
+ return MATMEDIA_MATERIAL;
+}
+
+S32 FSPanelFace::getCurrentMatChannel() const
+{
+ const std::string& tab_name = mTabsMatChannel->getCurrentPanel()->getName();
+
+ if (tab_name == "panel_blinn_phong_normal")
+ {
+ return MATTYPE_NORMAL;
+ }
+ if (tab_name == "panel_blinn_phong_specular")
+ {
+ return MATTYPE_SPECULAR;
+ }
+ return MATTYPE_DIFFUSE;
+}
+
+S32 FSPanelFace::getCurrentPBRChannel() const
+{
+ const std::string& tab_name = mTabsPBRChannel->getCurrentPanel()->getName();
+
+ if (tab_name == "panel_pbr_transforms_base_color")
+ {
+ return PBRTYPE_BASE_COLOR;
+ }
+ if (tab_name == "panel_pbr_transforms_normal")
+ {
+ return PBRTYPE_NORMAL;
+ }
+ if (tab_name == "panel_pbr_transforms_metallic")
+ {
+ return PBRTYPE_METALLIC_ROUGHNESS; // TODO: we use specular editor color for now -Zi
+ }
+ if (tab_name == "panel_pbr_transforms_emissive")
+ {
+ return PBRTYPE_EMISSIVE; // TODO: "emissive" has no defined editor color yet -Zi
+ }
+ return PBRTYPE_RENDER_MATERIAL_ID;
+}
+
+void FSPanelFace::selectMaterialType(S32 material_type)
+{
+ if (material_type == MATMEDIA_PBR)
+ {
+ mTabsPBRMatMedia->selectTabByName("panel_material_type_pbr");
+ }
+ else if (material_type == MATMEDIA_MEDIA)
+ {
+ mTabsPBRMatMedia->selectTabByName("panel_material_type_media");
+ }
+ else
+ {
+ mTabsPBRMatMedia->selectTabByName("panel_material_type_blinn_phong");
+ }
+ onMatTabChange(); // set up relative to active tab
+}
+
+void FSPanelFace::selectMatChannel(S32 mat_channel)
+{
+ if (mat_channel == MATTYPE_NORMAL)
+ {
+ mTabsMatChannel->selectTabByName("panel_blinn_phong_normal");
+ }
+ else if (mat_channel == MATTYPE_SPECULAR)
+ {
+ mTabsMatChannel->selectTabByName("panel_blinn_phong_specular");
+ }
+ else
+ {
+ mTabsMatChannel->selectTabByName("panel_blinn_phong_diffuse");
+ }
+}
+
+void FSPanelFace::selectPBRChannel(S32 pbr_channel)
+{
+ if (pbr_channel == PBRTYPE_NORMAL)
+ {
+ mTabsMatChannel->selectTabByName("panel_pbr_transforms_base_color");
+ }
+ else if (pbr_channel == PBRTYPE_BASE_COLOR)
+ {
+ mTabsMatChannel->selectTabByName("panel_pbr_transforms_normal");
+ }
+ else if (pbr_channel == PBRTYPE_METALLIC_ROUGHNESS)
+ {
+ mTabsMatChannel->selectTabByName("panel_pbr_transforms_metallic");
+ }
+ else if (pbr_channel == PBRTYPE_EMISSIVE)
+ {
+ mTabsMatChannel->selectTabByName("panel_pbr_transforms_emissive");
+ }
+ else
+ {
+ mTabsMatChannel->selectTabByName("panel_pbr_transforms_all");
+ }
+}
diff --git a/indra/newview/fspanelface.h b/indra/newview/fspanelface.h
new file mode 100644
index 0000000000..cdadee0e86
--- /dev/null
+++ b/indra/newview/fspanelface.h
@@ -0,0 +1,806 @@
+/**
+ * @file fspanelface.h
+ * @brief Consolidated materials/texture panel in the tools floater
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2024, Zi Ree@Second Life
+ *
+ * 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 FS_FSPANELFACE_H
+#define FS_FSPANELFACE_H
+
+#include "v4color.h"
+#include "llpanel.h"
+#include "llgltfmaterial.h"
+#include "llmaterial.h"
+#include "llmaterialmgr.h"
+#include "lltextureentry.h"
+#include "llselectmgr.h"
+
+#include
+
+class LLButton;
+class LLCheckBoxCtrl;
+class LLColorSwatchCtrl;
+class LLComboBox;
+class LLInventoryItem;
+class LLLineEditor;
+class LLRadioGroup;
+class LLSpinCtrl;
+class LLTextBox;
+class LLTextureCtrl;
+class LLUICtrl;
+class LLViewerObject;
+class LLFloater;
+class LLMaterialID;
+class LLMediaCtrl;
+class LLMenuButton;
+
+class PBRPickerAgentListener;
+class PBRPickerObjectListener;
+
+class LLTabContainer;
+
+// Represents an edit for use in replicating the op across one or more materials in the selection set.
+//
+// The apply function optionally performs the edit which it implements
+// as a functor taking Data that calls member func MaterialFunc taking SetValueType
+// on an instance of the LLMaterial class.
+//
+// boost who?
+//
+template<
+ typename DataType,
+ typename SetValueType,
+ void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+class FSMaterialEditFunctor
+{
+public:
+ FSMaterialEditFunctor(const DataType& data) : _data(data) {}
+ virtual ~FSMaterialEditFunctor() {}
+ virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); }
+ DataType _data;
+};
+
+template<
+ typename DataType,
+ DataType (LLMaterial::*MaterialGetFunc)() >
+class FSMaterialGetFunctor
+{
+public:
+ FSMaterialGetFunctor() {}
+ virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); }
+};
+
+template<
+ typename DataType,
+ DataType (LLTextureEntry::*TEGetFunc)() >
+class FSTEGetFunctor
+{
+public:
+ FSTEGetFunctor() {}
+ virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); }
+};
+
+//
+// main class
+//
+
+class FSPanelFace : public LLPanel
+{
+public:
+ FSPanelFace();
+ virtual ~FSPanelFace();
+
+ virtual BOOL postBuild();
+
+ void refresh();
+ void refreshMedia();
+ void unloadMedia();
+ void changePrecision(S32 decimal_precision); // Adjustable decimal precision
+
+ static void onMaterialOverrideReceived(const LLUUID& object_id, S32 side);
+
+ /*virtual*/ void onVisibilityChange(BOOL new_visibility);
+ /*virtual*/ void draw();
+
+ LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material);
+
+ LLRender::eTexIndex getTextureChannelToEdit();
+ LLRender::eTexIndex getTextureDropChannel();
+
+ LLGLTFMaterial::TextureInfo getPBRDropChannel();
+
+protected:
+ void navigateToTitleMedia(const std::string url);
+ bool selectedMediaEditable();
+ void clearMediaSettings();
+ void updateMediaSettings();
+ void updateMediaTitle();
+
+ void getState();
+
+ void sendTexture(); // applies and sends texture
+ void sendTextureInfo(); // applies and sends texture scale, offset, etc.
+ void sendColor(); // applies and sends color
+ void sendAlpha(); // applies and sends transparency
+ void sendBump(U32 bumpiness); // applies and sends bump map
+ void sendTexGen(); // applies and sends bump map
+ void sendShiny(U32 shininess); // applies and sends shininess
+ void sendFullbright(); // applies and sends full bright
+ void sendGlow();
+ void alignTextureLayer();
+
+ void updateCopyTexButton();
+
+ //
+ // UI Callbacks
+ //
+
+ // common controls and parameters for Blinn-Phong and PBR
+ void onCopyFaces(); // Extended copy & paste buttons
+ void onPasteFaces();
+ void onCommitGlow();
+ void onCommitRepeatsPerMeter();
+
+ // Blinn-Phong alpha parameters
+ void onCommitAlpha();
+ void onCommitAlphaMode();
+ void onCommitMaterialMaskCutoff();
+ void onCommitFullbright();
+
+ // Blinn-Phong texture transforms and controls
+ void onCommitTexGen();
+ void onCommitPlanarAlign();
+ void onCommitBump();
+ void onCommitShiny();
+ void onCommitTextureScaleX();
+ void onCommitTextureScaleY();
+ void onCommitTextureOffsetX();
+ void onCommitTextureOffsetY();
+ void onCommitTextureRot();
+ void onCommitMaterialBumpyScaleX();
+ void onCommitMaterialBumpyScaleY();
+ void onCommitMaterialBumpyOffsetX();
+ void onCommitMaterialBumpyOffsetY();
+ void onCommitMaterialBumpyRot();
+ void onCommitMaterialShinyScaleX();
+ void onCommitMaterialShinyScaleY();
+ void onCommitMaterialShinyOffsetX();
+ void onCommitMaterialShinyOffsetY();
+ void onCommitMaterialShinyRot();
+ void onCommitMaterialGloss();
+ void onCommitMaterialEnv();
+
+ // Blinn-Phong Diffuse tint color swatch
+ void onCommitColor();
+ void onCancelColor();
+ void onSelectColor();
+
+ // Blinn-Phong Diffuse texture swatch
+ void onCommitTexture(const LLUICtrl* ctrl, const LLSD& data);
+ void onCancelTexture();
+ BOOL onDragTexture(LLInventoryItem* item); // this function is to return TRUE if the drag should succeed.
+ void onCloseTexturePicker(const LLSD& data);
+
+ // Blinn-Phong Normal texture swatch
+ void onCommitNormalTexture(const LLUICtrl* ctrl, const LLSD& data);
+ void onCancelNormalTexture();
+
+ // Blinn-Phong Specular texture swatch
+ void onCommitSpecularTexture(const LLUICtrl* ctrl, const LLSD& data);
+ void onCancelSpecularTexture();
+
+ // Blinn-Phong Specular tint color swatch
+ void onCommitShinyColor();
+ void onCancelShinyColor();
+ void onSelectShinyColor();
+
+ // Texture alignment and maps synchronization
+ void onClickAutoFix();
+ void onAlignTexture();
+ void onClickMapsSync();
+
+ /*
+ * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
+ * If agent selects texture which is not allowed to be applied for the currently selected object,
+ * all controls of the floater texture picker which allow to apply the texture will be disabled.
+ */
+ void onTextureSelectionChanged(const std::string& which_control);
+
+ // Media
+ void onClickBtnEditMedia();
+ void onClickBtnDeleteMedia();
+ void onClickBtnAddMedia();
+
+ void alignMaterialsProperties();
+
+ //
+ // PBR
+ //
+
+ // PBR Material
+ void onCommitPbr();
+ void onCancelPbr();
+ void onSelectPbr();
+ BOOL onDragPbr(LLInventoryItem* item); // this function is to return TRUE if the drag should succeed.
+
+ void onPbrSelectionChanged(LLInventoryItem* itemp);
+ void onClickBtnSavePBR();
+
+ void updatePBROverrideDisplay();
+
+ // PBR texture maps
+ void onCommitPbr(const LLUICtrl* pbr_ctrl);
+ void onCancelPbr(const LLUICtrl* pbr_ctrl);
+ void onSelectPbr(const LLUICtrl* pbr_ctrl);
+
+ void getGLTFMaterial(LLGLTFMaterial* mat);
+
+ //
+ // other
+ //
+
+ bool deleteMediaConfirm(const LLSD& notification, const LLSD& response);
+ bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response);
+
+ // Make UI reflect state of currently selected material (refresh)
+ // and UI mode (e.g. editing normal map v diffuse map)
+ //
+ // @param force_set_values forces spinners to set value even if they are focused
+ void updateUI(bool force_set_values = false);
+
+ // Convenience func to determine if all faces in selection have
+ // identical planar texgen settings during edits
+ //
+ bool isIdenticalPlanarTexgen();
+
+ // Callback funcs for individual controls
+ //
+ static void syncRepeatX(FSPanelFace* self, F32 scaleU);
+ static void syncRepeatY(FSPanelFace* self, F32 scaleV);
+ static void syncOffsetX(FSPanelFace* self, F32 offsetU);
+ static void syncOffsetY(FSPanelFace* self, F32 offsetV);
+ static void syncMaterialRot(FSPanelFace* self, F32 rot, int te = -1);
+
+ // unify all GLTF spinners with no switching around required -Zi
+ void onCommitGLTFUVSpinner(const LLUICtrl* ctrl, const LLSD& user_data);
+
+ void onClickBtnSelectSameTexture(const LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture
+ void onShowFindAllButton(LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture
+ void onHideFindAllButton(LLUICtrl* ctrl, const LLSD& user_data); // Find all faces with same texture
+
+public: // needs to be accessible to selection manager
+ void onCopyColor(); // records all selected faces
+ void onPasteColor(); // to specific face
+ void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face
+ void onCopyTexture();
+ void onPasteTexture();
+ void onPasteTexture(LLViewerObject* objectp, S32 te);
+
+protected:
+ //
+ // Constant definitions for tabs and combo boxes
+ // Must match the commbobox definitions in panel_tools_texture.xml // Not anymore -Zi
+ //
+ static constexpr S32 MATMEDIA_MATERIAL = 0; // Material
+ static constexpr S32 MATMEDIA_PBR = 1; // PBR
+ static constexpr S32 MATMEDIA_MEDIA = 2; // Media
+
+ static constexpr S32 MATTYPE_DIFFUSE = 0; // Diffuse material texture
+ static constexpr S32 MATTYPE_NORMAL = 1; // Normal map
+ static constexpr S32 MATTYPE_SPECULAR = 2; // Specular map
+
+ static constexpr S32 BUMPY_TEXTURE = 18; // use supplied normal map (index of "Use Texture" in combo box)
+ static constexpr S32 SHINY_TEXTURE = 4; // use supplied specular map (index of "Use Texture" in combo box)
+
+ static constexpr S32 PBRTYPE_RENDER_MATERIAL_ID = 0; // Render Material ID
+ static constexpr S32 PBRTYPE_BASE_COLOR = 1; // PBR Base Color
+ static constexpr S32 PBRTYPE_METALLIC_ROUGHNESS = 2; // PBR Metallic
+ static constexpr S32 PBRTYPE_EMISSIVE = 3; // PBR Emissive
+ static constexpr S32 PBRTYPE_NORMAL = 4; // PBR Normal
+ static constexpr S32 PBRTYPE_COUNT = 5; // number of PBR map types
+
+public:
+ // public because ... functors? -Zi
+ void onCommitFlip(const LLSD& user_data);
+
+ // Blinn-Phong texture transforms and controls
+ // public because ... functors? -Zi
+ LLSpinCtrl* mCtrlTexScaleU;
+ LLSpinCtrl* mCtrlTexScaleV;
+ LLSpinCtrl* mCtrlBumpyScaleU;
+ LLSpinCtrl* mCtrlBumpyScaleV;
+ LLSpinCtrl* mCtrlShinyScaleU;
+ LLSpinCtrl* mCtrlShinyScaleV;
+ LLSpinCtrl* mCtrlTexOffsetU;
+ LLSpinCtrl* mCtrlTexOffsetV;
+ LLSpinCtrl* mCtrlBumpyOffsetU;
+ LLSpinCtrl* mCtrlBumpyOffsetV;
+ LLSpinCtrl* mCtrlShinyOffsetU;
+ LLSpinCtrl* mCtrlShinyOffsetV;
+ LLSpinCtrl* mCtrlTexRot;
+ LLSpinCtrl* mCtrlBumpyRot;
+ LLSpinCtrl* mCtrlShinyRot;
+
+ // Blinn-Phong texture transforms and controls
+ // public to give functors access -Zi
+ LLComboBox* mComboTexGen;
+ LLCheckBoxCtrl* mCheckPlanarAlign;
+
+ // Tab controls
+ // public to give functors access -Zi
+ LLTabContainer* mTabsMatChannel;
+ void onMatTabChange();
+
+private:
+ bool isAlpha() { return mIsAlpha; }
+
+ // Update visibility of controls to match current UI mode
+ // (e.g. materials vs media editing)
+ //
+ // Do NOT call updateUI from within this function.
+ //
+ void updateVisibility(LLViewerObject* objectp = nullptr);
+
+ // Convenience funcs to keep the visual flack to a minimum
+ //
+ LLUUID getCurrentNormalMap();
+ LLUUID getCurrentSpecularMap();
+ U32 getCurrentShininess();
+ U32 getCurrentBumpiness();
+ U8 getCurrentDiffuseAlphaMode();
+ U8 getCurrentAlphaMaskCutoff();
+ U8 getCurrentEnvIntensity();
+ U8 getCurrentGlossiness();
+ F32 getCurrentBumpyRot();
+ F32 getCurrentBumpyScaleU();
+ F32 getCurrentBumpyScaleV();
+ F32 getCurrentBumpyOffsetU();
+ F32 getCurrentBumpyOffsetV();
+ F32 getCurrentShinyRot();
+ F32 getCurrentShinyScaleU();
+ F32 getCurrentShinyScaleV();
+ F32 getCurrentShinyOffsetU();
+ F32 getCurrentShinyOffsetV();
+
+ // map tab states to various values
+ // TODO: should be done with tab-change signals and flags, really
+ S32 getCurrentMaterialType() const;
+ S32 getCurrentMatChannel() const;
+ S32 getCurrentPBRChannel() const;
+ void selectMaterialType(S32 material_type);
+ void selectMatChannel(S32 mat_channel);
+ void selectPBRChannel(S32 pbr_channel);
+
+ F32 getCurrentTextureRot();
+ F32 getCurrentTextureScaleU();
+ F32 getCurrentTextureScaleV();
+ F32 getCurrentTextureOffsetU();
+ F32 getCurrentTextureOffsetV();
+
+ //
+ // Build tool controls
+ //
+
+ // private Tab controls
+ LLTabContainer* mTabsPBRMatMedia;
+ LLTabContainer* mTabsPBRChannel;
+
+ // common controls and parameters for Blinn-Phong and PBR
+ LLButton* mBtnCopyFaces;
+ LLButton* mBtnPasteFaces;
+ LLSpinCtrl* mCtrlGlow;
+ LLSpinCtrl* mCtrlRpt;
+
+ // Blinn-Phong alpha parameters
+ LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha
+ LLView* mColorTransPercent;
+ LLTextBox* mLabelAlphaMode;
+ LLComboBox* mComboAlphaMode;
+ LLSpinCtrl* mCtrlMaskCutoff;
+ LLCheckBoxCtrl* mCheckFullbright;
+
+ // private Blinn-Phong texture transforms and controls
+ LLView* mLabelTexGen;
+ LLView* mLabelBumpiness;
+ LLComboBox* mComboBumpiness;
+ LLView* mLabelShininess;
+ LLComboBox* mComboShininess;
+ // others are above in the public section
+ LLSpinCtrl* mCtrlGlossiness;
+ LLSpinCtrl* mCtrlEnvironment;
+
+ // Blinn-Phong Diffuse tint color swatch
+ LLColorSwatchCtrl* mColorSwatch;
+
+ // Blinn-Phong Diffuse texture swatch
+ LLTextureCtrl* mTextureCtrl;
+
+ // Blinn-Phong Normal texture swatch
+ LLTextureCtrl* mBumpyTextureCtrl;
+
+ // Blinn-Phong Specular texture swatch
+ LLTextureCtrl* mShinyTextureCtrl;
+
+ // Blinn-Phong Specular tint color swatch
+ LLColorSwatchCtrl* mShinyColorSwatch;
+
+ // Texture alignment and maps synchronization
+ LLButton* mBtnAlignMedia;
+ LLButton* mBtnAlignTextures;
+ LLCheckBoxCtrl* mCheckSyncMaterials;
+
+ // Media
+ LLButton* mBtnDeleteMedia;
+ LLButton* mBtnAddMedia;
+ LLMediaCtrl* mTitleMedia;
+ LLTextBox* mTitleMediaText;
+
+ // PBR
+ LLTextureCtrl* mMaterialCtrlPBR;
+ LLColorSwatchCtrl* mBaseTintPBR;
+ LLTextureCtrl* mBaseTexturePBR;
+ LLTextureCtrl* mNormalTexturePBR;
+ LLTextureCtrl* mORMTexturePBR;
+ LLTextureCtrl* mEmissiveTexturePBR;
+ LLColorSwatchCtrl* mEmissiveTintPBR;
+ LLCheckBoxCtrl* mCheckDoubleSidedPBR;
+ LLSpinCtrl* mAlphaPBR;
+ LLTextBox* mLabelAlphaModePBR;
+ LLComboBox* mAlphaModePBR;
+ LLSpinCtrl* mMaskCutoffPBR;
+ LLSpinCtrl* mMetallicFactorPBR;
+ LLSpinCtrl* mRoughnessFactorPBR;
+ LLButton* mBtnSavePBR;
+
+ struct
+ {
+ std::array mMap;
+ LLColor4 mBaseColorTint;
+ F32 mMetallic;
+ F32 mRoughness;
+ LLColor4 mEmissiveTint;
+ LLGLTFMaterial::AlphaMode mAlphaMode;
+ F32 mAlphaCutoff;
+ bool mDoubleSided;
+ } mPBRBaseMaterialParams;
+
+ // map PBR material map types to glTF material types
+ LLGLTFMaterial::TextureInfo mPBRChannelToTextureInfo[PBRTYPE_COUNT] =
+ {
+ LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, // PBRTYPE_RENDER_MATERIAL_ID
+ LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR, // PBRTYPE_BASE_COLOR
+ LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, // PBRTYPE_METALLIC_ROUGHNESS
+ LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE, // PBRTYPE_EMISSIVE
+ LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL // PBRTYPE_NORMAL
+ };
+
+ // Dirty flags - taken from llmaterialeditor.cpp ... LL please put this in a .h! -Zi
+ U32 mUnsavedChanges; // flags to indicate individual changed parameters
+
+ // Hey look everyone, a type-safe alternative to copy and paste! :)
+ //
+
+ // Update material parameters by applying 'edit_func' to selected TEs
+ //
+ template<
+ typename DataType,
+ typename SetValueType,
+ void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+ static void edit(FSPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID())
+ {
+ FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data);
+ struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor
+ {
+ LLSelectedTEEditMaterial(FSPanelFace* panel, FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp, const LLUUID &only_for_object_id) : _panel(panel), _edit(editp), _only_for_object_id(only_for_object_id) {}
+ virtual ~LLSelectedTEEditMaterial() {};
+ virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material)
+ {
+ if (_edit && (_only_for_object_id.isNull() || _only_for_object_id == object->getID()))
+ {
+ LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material);
+ llassert_always(new_material);
+
+ // Determine correct alpha mode for current diffuse texture
+ // (i.e. does it have an alpha channel that makes alpha mode useful)
+ //
+ // _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
+ // need to get per-face answer to this question for sane alpha mode retention on updates.
+ //
+ bool is_alpha_face = object->isImageAlphaBlended(face);
+
+ // need to keep this original answer for valid comparisons in logic below
+ //
+ U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+ U8 default_alpha_mode = original_default_alpha_mode;
+
+ if (!current_material.isNull())
+ {
+ default_alpha_mode = current_material->getDiffuseAlphaMode();
+ }
+
+ // Insure we don't inherit the default of blend by accident...
+ // this will be stomped by a legit request to change the alpha mode by the apply() below
+ //
+ new_material->setDiffuseAlphaMode(default_alpha_mode);
+
+ // Do "It"!
+ //
+ _edit->apply(new_material);
+
+ U32 new_alpha_mode = new_material->getDiffuseAlphaMode();
+ LLUUID new_normal_map_id = new_material->getNormalID();
+ LLUUID new_spec_map_id = new_material->getSpecularID();
+
+ if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
+ {
+ new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+ new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+ }
+
+ bool is_default_blend_mode = (new_alpha_mode == original_default_alpha_mode);
+ bool is_need_material = !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
+
+ if (!is_need_material)
+ {
+ LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
+ LLMaterialMgr::getInstance()->remove(object->getID(),face);
+ new_material = NULL;
+ }
+ else
+ {
+ LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL;
+ LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
+ }
+
+ object->setTEMaterialParams(face, new_material);
+ return new_material;
+ }
+ return NULL;
+ }
+ FSMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* _edit;
+ FSPanelFace *_panel;
+ const LLUUID & _only_for_object_id;
+ } editor(p, &edit, only_for_object_id);
+ LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor, te);
+ }
+
+ template<
+ typename DataType,
+ typename ReturnType,
+ ReturnType (LLMaterial::* const MaterialGetFunc)() const >
+ static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
+ {
+ DataType data_value = default_value;
+ struct GetTEMaterialVal : public LLSelectedTEGetFunctor
+ {
+ GetTEMaterialVal(DataType default_value) : _default(default_value) {}
+ virtual ~GetTEMaterialVal() {}
+
+ DataType get(LLViewerObject* object, S32 face)
+ {
+ DataType ret = _default;
+ LLMaterialPtr material_ptr;
+ LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+ if (tep)
+ {
+ material_ptr = tep->getMaterialParams();
+ if (!material_ptr.isNull())
+ {
+ ret = (material_ptr->*(MaterialGetFunc))();
+ }
+ }
+ return ret;
+ }
+ DataType _default;
+ } GetFunc(default_value);
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value, has_tolerance, tolerance);
+ data_to_return = data_value;
+ }
+
+ template<
+ typename DataType,
+ typename ReturnType, // some kids just have to different...
+ ReturnType (LLTextureEntry::* const TEGetFunc)() const >
+ static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value, bool has_tolerance = false, DataType tolerance = DataType())
+ {
+ DataType data_value = default_value;
+ struct GetTEVal : public LLSelectedTEGetFunctor
+ {
+ GetTEVal(DataType default_value) : _default(default_value) {}
+ virtual ~GetTEVal() {}
+
+ DataType get(LLViewerObject* object, S32 face) {
+ LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+ return tep ? ((tep->*(TEGetFunc))()) : _default;
+ }
+ DataType _default;
+ } GetTEValFunc(default_value);
+ identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value, has_tolerance, tolerance );
+ data_to_return = data_value;
+ }
+
+ // Update vis and enabling of specific subsets of controls based on material params
+ // (e.g. hide the spec controls if no spec texture is applied)
+ //
+ void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+ void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+ void updateAlphaControls();
+ void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool& has_faces_without_pbr, bool force_set_values);
+
+ void updateSelectedGLTFMaterials(std::function func);
+ void updateGLTFTextureTransform(float value, U32 pbr_type, std::function edit);
+
+ void setMaterialOverridesFromSelection();
+
+ bool mIsAlpha;
+
+ LLSD mClipboardParams;
+
+ LLSD mMediaSettings;
+ bool mNeedMediaTitle;
+
+ class Selection
+ {
+ public:
+ void connect();
+
+ // Returns true if the selected objects or sides have changed since
+ // this was last called, and no object update is pending
+ bool update();
+
+ // Prevents update() returning true until the provided object is
+ // updated. Necessary to prevent controls updating when the mouse is
+ // held down.
+ void setDirty() { mChanged = true; };
+
+ // Callbacks
+ void onSelectionChanged() { mNeedsSelectionCheck = true; }
+ void onSelectedObjectUpdated(const LLUUID &object_id, S32 side);
+
+ protected:
+ bool compareSelection();
+
+ bool mChanged = false;
+
+ boost::signals2::scoped_connection mSelectConnection;
+ bool mNeedsSelectionCheck = true;
+ S32 mSelectedObjectCount = 0;
+ S32 mSelectedTECount = 0;
+ LLUUID mSelectedObjectID;
+ S32 mLastSelectedSide = -1;
+ };
+
+ static Selection sMaterialOverrideSelection;
+
+ std::unique_ptr mAgentInventoryListener;
+ std::unique_ptr mVOInventoryListener;
+
+public:
+ #if defined(FS_DEF_GET_MAT_STATE)
+ #undef FS_DEF_GET_MAT_STATE
+ #endif
+
+ #if defined(FS_DEF_GET_TE_STATE)
+ #undef FS_DEF_GET_TE_STATE
+ #endif
+
+ #if defined(FS_DEF_EDIT_MAT_STATE)
+ FS_DEF_EDIT_MAT_STATE
+ #endif
+
+ // Accessors for selected TE material state
+ //
+ #define FS_DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue,HasTolerance,Tolerance) \
+ static void MaterialMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance) \
+ { \
+ getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance); \
+ }
+
+ // Mutators for selected TE material
+ //
+ #define FS_DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc) \
+ static void MaterialMemberFunc(FSPanelFace* p, DataType data, int te = -1, const LLUUID &only_for_object_id = LLUUID()) \
+ { \
+ edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p, data, te, only_for_object_id); \
+ }
+
+ // Accessors for selected TE state proper (legacy settings etc)
+ //
+ #define FS_DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue,HasTolerance,Tolerance) \
+ static void TexEntryMemberFunc(DataType& data, bool& identical, bool has_tolerance = HasTolerance, DataType tolerance = Tolerance) \
+ { \
+ getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical, DefaultValue, has_tolerance, tolerance); \
+ }
+
+ class LLSelectedTEMaterial
+ {
+ public:
+ static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
+ static void getMaxSpecularRepeats(F32& repeats, bool& identical);
+ static void getMaxNormalRepeats(F32& repeats, bool& identical);
+ static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
+
+ FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null, false, LLUUID::null)
+ FS_DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null, false, LLUUID::null)
+ FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f, true, 0.001f)
+
+ FS_DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f, true, 0.001f)
+ FS_DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f, true, 0.001f)
+
+ FS_DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
+ FS_DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
+
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation);
+
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY);
+ FS_DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation);
+
+ FS_DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity);
+ FS_DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent);
+
+ FS_DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
+ FS_DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
+ FS_DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor);
+ };
+
+ class LLSelectedTE
+ {
+ public:
+ static void getFace(class LLFace*& face_to_return, bool& identical_face);
+ static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
+ static void getTexId(LLUUID& id, bool& identical);
+ static void getObjectScaleS(F32& scale_s, bool& identical);
+ static void getObjectScaleT(F32& scale_t, bool& identical);
+ static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
+
+ FS_DEF_GET_TE_STATE(U8,U8,getBumpmap,0, false, 0)
+ FS_DEF_GET_TE_STATE(U8,U8,getShiny,0, false, 0)
+ FS_DEF_GET_TE_STATE(U8,U8,getFullbright,0, false, 0)
+ FS_DEF_GET_TE_STATE(F32,F32,getRotation,0.0f, true, 0.001f)
+ FS_DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f, true, 0.001f)
+ FS_DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f, true, 0.001f)
+ FS_DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f, true, 0.001f)
+ FS_DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f, true, 0.001f)
+ FS_DEF_GET_TE_STATE(F32,F32,getGlow,0.0f, true, 0.001f)
+ FS_DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT, false, LLTextureEntry::TEX_GEN_DEFAULT)
+ FS_DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white, false, LLColor4::black);
+ };
+};
+
+#endif
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4775686fc0..467c7e1d69 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1395,6 +1395,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
LLMaterial* mat = tep ? tep->getMaterialParams().get() : 0;
//
LLGLTFMaterial* gltf_mat = tep->getGLTFRenderMaterial();
+ // show legacy when editing the fallback materials.
+ static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong");
+ if( gltf_mat && getViewerObject()->isSelected() && showSelectedinBP )
+ {
+ gltf_mat = nullptr;
+ }
+ //
F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index d765327925..ef5b19ba2d 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -94,6 +94,8 @@
#include "llvograss.h"
#include "llvotree.h"
+#include "fspanelface.h" // switchable edit texture/materials panel
+
// Globals
LLFloaterTools *gFloaterTools = NULL;
bool LLFloaterTools::sShowObjectCost = true;
@@ -174,8 +176,14 @@ void* LLFloaterTools::createPanelVolume(void* data)
void* LLFloaterTools::createPanelFace(void* data)
{
LLFloaterTools* floater = (LLFloaterTools*)data;
- floater->mPanelFace = new LLPanelFace();
- return floater->mPanelFace;
+
+ // switchable edit texture/materials panel
+ // we should not need this here at all, we are adding the texture/materials
+ // panel in postBuild()
+ // floater->mPanelFace = new LLPanelFace();
+ // return floater->mPanelFace;
+ return floater->findChild("Texture");
+ //
}
//static
@@ -229,6 +237,27 @@ LLPCode toolData[]={
BOOL LLFloaterTools::postBuild()
{
+ // switchable edit texture/materials panel
+ LLPanel* panel;
+ if (gSavedSettings.getBOOL("FSUseNewTexturePanel"))
+ {
+ mFSPanelFace = new FSPanelFace;
+ panel = mFSPanelFace;
+ }
+ else
+ {
+ mPanelFace = new LLPanelFace;
+ panel = mPanelFace;
+ }
+
+ LLTabContainer::TabPanelParams params;
+ params.panel = panel;
+ params.insert_at = (LLTabContainer::eInsertionPoint) PANEL_FACE;
+
+ mTab = getChild("Object Info Tabs");
+ mTab->addTabPanel(params);
+ //
+
// Hide until tool selected
setVisible(FALSE);
@@ -367,7 +396,11 @@ void LLFloaterTools::changePrecision(S32 decimal_precision)
else if (decimal_precision > 7) decimal_precision = 7;
mPanelObject->changePrecision(decimal_precision);
- mPanelFace->changePrecision(decimal_precision);
+ // switchable edit texture/materials panel
+ // mPanelFace->changePrecision(decimal_precision);
+ if (mPanelFace) mPanelFace->changePrecision(decimal_precision);
+ if (mFSPanelFace) mFSPanelFace->changePrecision(decimal_precision);
+ //
}
// Create the popupview with a dummy center. It will be moved into place
@@ -431,6 +464,7 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
mPanelVolume(NULL),
mPanelContents(NULL),
mPanelFace(NULL),
+ mFSPanelFace(nullptr), // switchable edit texture/materials panel
mPanelLandInfo(NULL),
mCostTextBorder(NULL),
@@ -470,7 +504,6 @@ LLFloaterTools::LLFloaterTools(const LLSD& key)
//
mCommitCallbackRegistrar.add("BuildTool.CopyKeys", boost::bind(&LLFloaterTools::onClickBtnCopyKeys,this));
mCommitCallbackRegistrar.add("BuildTool.Expand", boost::bind(&LLFloaterTools::onClickExpand,this));
- mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&LLPanelFace::onCommitFlip, _1, _2));
//
// FIRE-7802: Grass and tree selection in build tool
@@ -744,8 +777,20 @@ void LLFloaterTools::refresh()
mPanelPermissions->refresh();
mPanelObject->refresh();
mPanelVolume->refresh();
- mPanelFace->refresh();
- mPanelFace->refreshMedia();
+ // switchable edit texture/materials panel
+ // mPanelFace->refresh();
+ // mPanelFace->refreshMedia();
+ if (mPanelFace)
+ {
+ mPanelFace->refresh();
+ mPanelFace->refreshMedia();
+ }
+ if (mFSPanelFace)
+ {
+ mFSPanelFace->refresh();
+ mFSPanelFace->refreshMedia();
+ }
+ //
mPanelContents->refresh();
mPanelLandInfo->refresh();
@@ -1142,7 +1187,11 @@ void LLFloaterTools::onClose(bool app_quitting)
LLViewerJoystick::getInstance()->moveAvatar(false);
// destroy media source used to grab media title
- mPanelFace->unloadMedia();
+ // switchable edit texture/materials panel
+ // mPanelFace->unloadMedia();
+ if (mPanelFace) mPanelFace->unloadMedia();
+ if (mFSPanelFace) mFSPanelFace->unloadMedia();
+ //
// Different from handle_reset_view in that it doesn't actually
// move the camera if EditCameraMovement is not set.
@@ -1626,3 +1675,39 @@ void LLFloaterTools::onSelectTreeGrassCombo()
}
}
//
+
+// switchable edit texture/materials panel
+void LLFloaterTools::refreshPanelFace()
+{
+ if (mPanelFace) mPanelFace->refresh();
+ if (mFSPanelFace) mFSPanelFace->refresh();
+}
+
+LLRender::eTexIndex LLFloaterTools::getTextureDropChannel()
+{
+ if (mPanelFace) return mPanelFace->getTextureDropChannel();
+ if (mFSPanelFace) return mFSPanelFace->getTextureDropChannel();
+ return LLRender::NUM_TEXTURE_CHANNELS; // invalid
+}
+
+LLRender::eTexIndex LLFloaterTools::getTextureChannelToEdit()
+{
+ if (mPanelFace) return mPanelFace->getTextureChannelToEdit();
+ if (mFSPanelFace) return mFSPanelFace->getTextureChannelToEdit();
+ return LLRender::NUM_TEXTURE_CHANNELS; // invalid
+}
+
+LLGLTFMaterial::TextureInfo LLFloaterTools::getPBRDropChannel()
+{
+ if (mPanelFace) return mPanelFace->getPBRDropChannel();
+ if (mFSPanelFace) return mFSPanelFace->getPBRDropChannel();
+ return LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; // invalid
+}
+
+LLMaterialPtr LLFloaterTools::createDefaultMaterial(LLMaterialPtr old_mat)
+{
+ if (mPanelFace) return mPanelFace->createDefaultMaterial(old_mat);
+ if (mFSPanelFace) return mFSPanelFace->createDefaultMaterial(old_mat);
+ return nullptr; // invalid
+}
+//
diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h
index eec968d815..2ea5daaf93 100644
--- a/indra/newview/llfloatertools.h
+++ b/indra/newview/llfloatertools.h
@@ -50,6 +50,14 @@ class LLParcelSelection;
class LLObjectSelection;
class LLLandImpactsObserver;
+// switchable edit texture/materials panel
+#include "llgltfmaterial.h"
+#include "llmaterial.h"
+#include "llrender.h"
+
+class FSPanelFace;
+//
+
typedef LLSafeHandle LLObjectSelectionHandle;
class LLFloaterTools
@@ -107,7 +115,14 @@ public:
static void setGridMode(S32 mode);
- LLPanelFace* getPanelFace() { return mPanelFace; }
+ // switchable edit texture/materials panel
+ // LLPanelFace* getPanelFace() { return mPanelFace; }
+ LLRender::eTexIndex getTextureDropChannel();
+ LLRender::eTexIndex getTextureChannelToEdit();
+ LLGLTFMaterial::TextureInfo getPBRDropChannel();
+ LLMaterialPtr createDefaultMaterial(LLMaterialPtr old_mat);
+ void refreshPanelFace();
+ //
void onClickBtnCopyKeys();
void onClickExpand();
@@ -193,7 +208,7 @@ public:
LLPanelObject *mPanelObject;
LLPanelVolume *mPanelVolume;
LLPanelContents *mPanelContents;
- LLPanelFace *mPanelFace;
+// LLPanelFace *mPanelFace; // switchable edit texture/materials panel
LLPanelLandInfo *mPanelLandInfo;
LLViewBorder* mCostTextBorder;
@@ -215,6 +230,9 @@ private:
S32 mExpandedHeight;
std::map mStatusText;
+ LLPanelFace* mPanelFace; // switchable edit texture/materials panel
+ FSPanelFace* mFSPanelFace; // switchable edit texture/materials panel
+
public:
static bool sShowObjectCost;
static bool sPreviousFocusOnAvatar;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 6143151fe8..b5f055b879 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -603,6 +603,8 @@ LLPanelFace::LLPanelFace()
mTitleMediaText(NULL),
mNeedMediaTitle(true)
{
+ buildFromFile("panel_tools_texture.xml"); // switchable edit texture/materials
+
USE_TEXTURE = LLTrans::getString("use_texture");
// Extended copy & paste buttons
//mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2));
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index a4bdf6950a..bc519ed7ef 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -97,7 +97,7 @@
#include "llvovolume.h"
#include "pipeline.h"
#include "llviewershadermgr.h"
-#include "llpanelface.h"
+// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
#include "rlvactions.h"
#include "rlvhandler.h"
@@ -1919,8 +1919,52 @@ bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* i
//-----------------------------------------------------------------------------
// selectionSetImage()
//-----------------------------------------------------------------------------
+// Allow editing of non-PBR materials in-situ
+template
+struct TextureApplyFunctor : public LLSelectedTEFunctor
+{
+ LLViewerInventoryItem* mItem;
+ LLUUID mImageID;
+ TextureApplyFunctor(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {}
+ bool apply(LLViewerObject* objectp, S32 te) override
+ {
+ if(!objectp || !objectp->permModify())
+ {
+ return false;
+ }
+
+ if (mItem && objectp->isAttachment())
+ {
+ const LLPermissions& perm = mItem->getPermissions();
+ BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
+ if (!unrestricted)
+ {
+ return false;
+ }
+ }
+
+ if (mItem)
+ {
+ if constexpr (IsPBR)
+ {
+ LLToolDragAndDrop::dropTextureOneFace(objectp, te, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false);
+ }
+ else
+ {
+ LLToolDragAndDrop::dropTextureOneFace(objectp, te, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null, false, -2); // -2 means no PBR
+ }
+ }
+ else // not an inventory item
+ {
+ objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+ }
+
+ return true;
+ }
+};
+//
// *TODO: re-arch texture applying out of lltooldraganddrop
-bool LLSelectMgr::selectionSetImage(const LLUUID& imageid)
+bool LLSelectMgr::selectionSetImage(const LLUUID& imageid, bool isPBR)
{
// First for (no copy) textures and multiple object selection
LLViewerInventoryItem* item = gInventory.getItem(imageid);
@@ -1935,60 +1979,73 @@ bool LLSelectMgr::selectionSetImage(const LLUUID& imageid)
return false;
}
- struct f : public LLSelectedTEFunctor
- {
- LLViewerInventoryItem* mItem;
- LLUUID mImageID;
- f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {}
- bool apply(LLViewerObject* objectp, S32 te)
- {
- if(!objectp || !objectp->permModify())
- {
- return false;
- }
+ // Allow editing of non-PBR materials in-situ
+ // struct f : public LLSelectedTEFunctor
+ // {
+ // LLViewerInventoryItem* mItem;
+ // LLUUID mImageID;
+ // f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {}
+ // bool apply(LLViewerObject* objectp, S32 te)
+ // {
+ // if(!objectp || !objectp->permModify())
+ // {
+ // return false;
+ // }
- // Might be better to run willObjectAcceptInventory
- if (mItem && objectp->isAttachment())
- {
- const LLPermissions& perm = mItem->getPermissions();
- BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
- if (!unrestricted)
- {
- // Attachments are in world and in inventory simultaneously,
- // at the moment server doesn't support such a situation.
- return false;
- }
- }
+ // // Might be better to run willObjectAcceptInventory
+ // if (mItem && objectp->isAttachment())
+ // {
+ // const LLPermissions& perm = mItem->getPermissions();
+ // BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
+ // if (!unrestricted)
+ // {
+ // // Attachments are in world and in inventory simultaneously,
+ // // at the moment server doesn't support such a situation.
+ // return false;
+ // }
+ // }
- if (mItem)
- {
- LLToolDragAndDrop::dropTextureOneFace(objectp,
- te,
- mItem,
- LLToolDragAndDrop::SOURCE_AGENT,
- LLUUID::null,
- false);
- }
- else // not an inventory item
- {
- // Texture picker defaults aren't inventory items
- // * Don't need to worry about permissions for them
- // * Can just apply the texture and be done with it.
- objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
- }
-
- return true;
- }
- };
+ // if (mItem)
+ // {
+ // LLToolDragAndDrop::dropTextureOneFace(objectp,
+ // te,
+ // mItem,
+ // LLToolDragAndDrop::SOURCE_AGENT,
+ // LLUUID::null,
+ // false);
+ // }
+ // else // not an inventory item
+ // {
+ // // Texture picker defaults aren't inventory items
+ // // * Don't need to worry about permissions for them
+ // // * Can just apply the texture and be done with it.
+ // objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+ // }
+ // return true;
+ // }
+ // };
+ //
if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
{
getSelection()->applyNoCopyTextureToTEs(item);
}
else
{
- f setfunc(item, imageid);
- getSelection()->applyToTEs(&setfunc);
+ // Allow editing of non-PBR materials in-situ
+ // f setfunc(item, imageid);
+ // getSelection()->applyToTEs(&setfunc);
+ TextureApplyFunctor setfuncPBR(item, imageid); // For PBR textures
+ TextureApplyFunctor setfuncBP(item, imageid); // For non-PBR textures
+ if(isPBR)
+ {
+ getSelection()->applyToTEs(&setfuncPBR);
+ }
+ else
+ {
+ getSelection()->applyToTEs(&setfuncBP);
+ }
+ //
}
@@ -2258,7 +2315,9 @@ void LLSelectMgr::selectionRevertShinyColors()
LLMaterialPtr old_mat = object->getTEref(te).getMaterialParams();
if (!old_mat.isNull())
{
- LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat);
+ // switchable edit texture/materials panel
+ // LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat);
+ LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat);
new_mat->setSpecularLightColor(color);
object->getTEref(te).setMaterialParams(new_mat);
LLMaterialMgr::getInstance()->put(object->getID(), te, *new_mat);
@@ -3174,7 +3233,9 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch)
if (tep && !tep->getMaterialParams().isNull())
{
LLMaterialPtr orig = tep->getMaterialParams();
- LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
+ // switchable edit texture/materials panel
+ // LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
+ LLMaterialPtr p = gFloaterTools->createDefaultMaterial(orig);
p->setNormalRepeat(normal_scale_s, normal_scale_t);
p->setSpecularRepeat(specular_scale_s, specular_scale_t);
@@ -3200,7 +3261,9 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch)
if (tep && !tep->getMaterialParams().isNull())
{
LLMaterialPtr orig = tep->getMaterialParams();
- LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
+ // switchable edit texture/materials panel
+ // LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
+ LLMaterialPtr p = gFloaterTools->createDefaultMaterial(orig);
p->setNormalRepeat(normal_scale_s, normal_scale_t);
p->setSpecularRepeat(specular_scale_s, specular_scale_t);
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 0902fc1b39..5bea652f10 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -717,7 +717,7 @@ public:
void selectionSetDensity(F32 density);
void selectionSetRestitution(F32 restitution);
void selectionSetMaterial(U8 material);
- bool selectionSetImage(const LLUUID& imageid); // could be item or asset id
+ bool selectionSetImage(const LLUUID& imageid, bool isPBR=true); // inject PBR awareness.
bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only
void selectionSetColor(const LLColor4 &color);
void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 5f03f80327..6a115f4021 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -60,7 +60,12 @@
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llworld.h"
-#include "llpanelface.h"
+// switchable edit texture/materials panel
+// #include "llpanelface.h"
+#include "llmaterial.h"
+#include "llmaterialmgr.h"
+//
+
#include "lluiusage.h"
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1)
#include "rlvactions.h"
@@ -1412,11 +1417,14 @@ void LLToolDragAndDrop::dropTexture(LLViewerObject* hit_obj,
// If user dropped a texture onto face it implies
// applying texture now without cancel, save to selection
- LLPanelFace* panel_face = gFloaterTools->getPanelFace();
+ // LLPanelFace* panel_face = gFloaterTools->getPanelFace(); // switchable edit texture/materials panel
if (nodep
&& gFloaterTools->getVisible()
- && panel_face
- && panel_face->getTextureDropChannel() == 0 /*texture*/
+ // switchable edit texture/materials panel
+ // && panel_face
+ // && panel_face->getTextureDropChannel() == 0 /*texture*/
+ && gFloaterTools->getTextureDropChannel() == 0 /*texture*/
+ //
&& nodep->mSavedTextures.size() > hit_face)
{
LLViewerTexture* tex = hit_obj->getTEImage(hit_face);
@@ -1459,7 +1467,7 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
LLUUID asset_id = item->getAssetUUID();
- if (hit_obj->getRenderMaterialID(hit_face).notNull() && !remove_pbr)
+ if (hit_obj->getRenderMaterialID(hit_face).notNull() && !remove_pbr && tex_channel >= -1) // tex_channel -2 means ignorePBR then treat as -1, don't judge me.
{
// Overrides require textures to be copy and transfer free
LLPermissions item_permissions = item->getPermissions();
@@ -1469,16 +1477,28 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
if (allow_adding_to_override)
{
LLGLTFMaterial::TextureInfo drop_channel = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR;
- LLPanelFace* panel_face = gFloaterTools->getPanelFace();
- if (gFloaterTools->getVisible() && panel_face)
+ // switchable edit texture/materials panel
+ // LLPanelFace* panel_face = gFloaterTools->getPanelFace();
+ // if (gFloaterTools->getVisible() && panel_face)
+ // {
+ // drop_channel = panel_face->getPBRDropChannel();
+ // }
+ if (gFloaterTools->getVisible())
{
- drop_channel = panel_face->getPBRDropChannel();
+ drop_channel = gFloaterTools->getPBRDropChannel();
}
+ //
set_texture_to_material(hit_obj, hit_face, asset_id, drop_channel);
LLGLTFMaterialList::flushUpdates(nullptr);
}
return;
}
+ // tex_channel -2 means ignorePBR then treat as -1
+ if(tex_channel < -1)
+ {
+ tex_channel = -1;
+ }
+ //
BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
if (!success)
{
@@ -1495,11 +1515,16 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
LLTextureEntry* tep = hit_obj->getTE(hit_face);
- LLPanelFace* panel_face = gFloaterTools->getPanelFace();
+ // switchable edit texture/materials panel
+ // LLPanelFace* panel_face = gFloaterTools->getPanelFace();
- if (gFloaterTools->getVisible() && panel_face)
+ // if (gFloaterTools->getVisible() && panel_face)
+ if (gFloaterTools->getVisible())
+ //
{
- tex_channel = (tex_channel > -1) ? tex_channel : panel_face->getTextureDropChannel();
+ // switchable edit texture/materials panel
+ // tex_channel = (tex_channel > -1) ? tex_channel : panel_face->getTextureDropChannel();
+ tex_channel = (tex_channel > -1) ? tex_channel : gFloaterTools->getTextureDropChannel();
switch (tex_channel)
{
@@ -1514,7 +1539,9 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
if (tep)
{
LLMaterialPtr old_mat = tep->getMaterialParams();
- LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat);
+ // switchable edit texture/materials panel
+ // LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat);
+ LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat);
new_mat->setNormalID(asset_id);
tep->setMaterialParams(new_mat);
hit_obj->setTENormalMap(hit_face, asset_id);
@@ -1526,7 +1553,9 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
if (tep)
{
LLMaterialPtr old_mat = tep->getMaterialParams();
- LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat);
+ // switchable edit texture/materials panel
+ // LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat);
+ LLMaterialPtr new_mat = gFloaterTools->createDefaultMaterial(old_mat);
new_mat->setSpecularID(asset_id);
tep->setMaterialParams(new_mat);
hit_obj->setTESpecularMap(hit_face, asset_id);
diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp
index 0fa7c6c3a0..66588d2d5a 100644
--- a/indra/newview/lltoolface.cpp
+++ b/indra/newview/lltoolface.cpp
@@ -43,8 +43,8 @@
#include "rlvactions.h"
// [/RLVa:KB]
+// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed
// Add control to drag texture faces around
-#include "llpanelface.h"
#include "llspinctrl.h"
#include "llkeyboard.h"
#include "llwindow.h"
@@ -290,11 +290,14 @@ void LLToolFace::render()
LLFloaterTools* toolsFloater=(LLFloaterTools*) LLFloaterReg::findInstance("build");
if(toolsFloater)
{
- LLPanelFace* panelFace=toolsFloater->mPanelFace;
- if(panelFace)
- {
- panelFace->refresh();
- }
+ // switchable edit texture/materials panel
+ // LLPanelFace* panelFace=toolsFloater->mPanelFace;
+ // if(panelFace)
+ // {
+ // panelFace->refresh();
+ // }
+ toolsFloater->refreshPanelFace();
+ //
}
#ifdef TEXTURE_GRAB_UPDATE_REGULARLY
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index ca047d89c1..d90e193f09 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -5521,6 +5521,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
const LLMatrix4* model_mat = NULL;
LLDrawable* drawable = facep->getDrawable();
+ if(!drawable)
+ {
+ return;
+ }
if (rigged)
{
@@ -5556,6 +5560,15 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
auto* gltf_mat = (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial();
llassert(gltf_mat == nullptr || dynamic_cast(te->getGLTFRenderMaterial()) != nullptr);
+
+ // show legacy when editing the fallback materials.
+ static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong");
+ if( gltf_mat && facep->getViewerObject()->isSelected() && showSelectedinBP )
+ {
+ gltf_mat = nullptr;
+ }
+ //
+
if (gltf_mat != nullptr)
{
mat_id = gltf_mat->getHash(); // TODO: cache this hash
@@ -6786,6 +6799,14 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
const LLTextureEntry* te = facep->getTextureEntry();
LLGLTFMaterial* gltf_mat = te->getGLTFRenderMaterial();
+
+ // show legacy when editing the fallback materials.
+ static LLCachedControl showSelectedinBP(gSavedSettings, "FSShowSelectedInBlinnPhong");
+ if( gltf_mat && facep->getViewerObject()->isSelected() && showSelectedinBP )
+ {
+ gltf_mat = nullptr;
+ }
+ //
if (hud_group && gltf_mat == nullptr)
{ //all hud attachments are fullbright
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 14d2830296..f8e23347f5 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -107,7 +107,7 @@
#include "llfloaterpathfindingconsole.h"
#include "llfloaterpathfindingcharacters.h"
#include "llfloatertools.h"
-#include "llpanelface.h"
+// #include "llpanelface.h" // switchable edit texture/materials panel - include not needed
#include "llpathfindingpathtool.h"
#include "llscenemonitor.h"
#include "llprogressview.h"
@@ -3660,7 +3660,9 @@ void LLPipeline::postSort(LLCamera &camera)
if (!gNonInteractive)
{
- LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+ // switchable edit texture/materials panel
+ // LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
+ LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getTextureChannelToEdit());
}
// Draw face highlights for selected faces.
diff --git a/indra/newview/skins/default/xui/az/floater_beacons.xml b/indra/newview/skins/default/xui/az/floater_beacons.xml
index 569d019fcb..35be748764 100644
--- a/indra/newview/skins/default/xui/az/floater_beacons.xml
+++ b/indra/newview/skins/default/xui/az/floater_beacons.xml
@@ -20,7 +20,7 @@
-
+
Göstərmə istiqaməti:
diff --git a/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml
index 863f3de86e..e7b294d810 100644
--- a/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml
+++ b/indra/newview/skins/default/xui/az/floater_scene_load_stats.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/az/notifications.xml b/indra/newview/skins/default/xui/az/notifications.xml
index 9adbebf57b..326552c1a1 100644
--- a/indra/newview/skins/default/xui/az/notifications.xml
+++ b/indra/newview/skins/default/xui/az/notifications.xml
@@ -3738,7 +3738,7 @@ Siz [TIME] saniyədən sonra '[BODYREGION]' üçün [RESOLUTION] bişmiş tekstu
Siz [TIME] saniyədən sonra '[BODYREGION]' üçün [RESOLUTION] bişmiş teksturasını yerli olaraq yenilədiniz.
- Teksturanı yükləmək mümkün deyil.
+ Teksturanı yükləmək mümkün deyil: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/default/xui/az/panel_profile_pick.xml b/indra/newview/skins/default/xui/az/panel_profile_pick.xml
index 5c4057a6c4..3b7121dd11 100644
--- a/indra/newview/skins/default/xui/az/panel_profile_pick.xml
+++ b/indra/newview/skins/default/xui/az/panel_profile_pick.xml
@@ -10,8 +10,8 @@
Məkan:
Yüklənir...
-
-
+
+
diff --git a/indra/newview/skins/default/xui/de/panel_fs_tools_texture.xml b/indra/newview/skins/default/xui/de/panel_fs_tools_texture.xml
new file mode 100644
index 0000000000..16f3da7d54
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/panel_fs_tools_texture.xml
@@ -0,0 +1,390 @@
+
+
+
+ Falls mehrere Flächen kopiert werden, müssen auf dem Zielobjekt dieselbe Anzahl an Flächen selektiert sein.
+
+
+ Falls alle Flächen eines Objekts kopiert werden, muss das Zielobjekt dieselbe Anzahl an Flächen besitzen.
+
+
+ Eine oder mehrere Texturen wurden nicht im Inventar gefunden.
+
+
+ Textur-Parameter in Zwischenablage kopieren
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Modus
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Skalierung
+
+
+ U
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ U
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+ Skalierung
+
+
+ U
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ U
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+ Skalierung
+
+
+ U
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ U
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+ Skalierung
+
+
+ U
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ U
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+ Skalierung
+
+
+ U
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ U
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %
+
+
+ Alpha-Modus
+
+
+
+
+
+
+
+
+
+ Holprigkeit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Glänzen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Skalierung
+
+
+ H
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ H
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+ Skalierung
+
+
+ H
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ H
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+ Skalierung
+
+
+ H
+
+
+
+ V
+
+
+
+
+
+ Versatz
+
+
+ H
+
+
+ V
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+ Ausgewählte Medien-URL
+
+
+
+
+
+
+
+
+
+
+
+ Mapping
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 2be08c3f83..9ce95d8368 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -3238,8 +3238,10 @@ Low ↔ Lwst
+
+
+
+
+ When multiple faces are copied, the target object must have the same number of faces selected.
+
+
+ When all faces of an object are copied, the target object must have the same number of faces.
+
+
+ One or more textures not found in inventory.
+
+
+ Copy Texture Parameters to Clipboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ U
+
+
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ U
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ U
+
+
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ U
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ U
+
+
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ U
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ U
+
+
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ U
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ U
+
+
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ U
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %
+
+
+
+ Alpha mode
+
+
+
+
+
+
+
+
+
+
+
+
+ Bumpiness
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Shininess
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ H
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ H
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ H
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ H
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Scale
+
+
+
+ H
+
+
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+
+
+ Offset
+
+
+
+ H
+
+
+
+
+
+ V
+
+
+
+
+
+
+
+
+
+ Rotation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ URL of chosen media, if any, goes here
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mapping
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_firestorm.xml b/indra/newview/skins/default/xui/en/panel_preferences_firestorm.xml
index 41dda40ed8..ae08cdd5de 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_firestorm.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_firestorm.xml
@@ -1654,6 +1654,14 @@
tool_tip="If enabled, the list of attachments spots in the &Attach to& menus will be sorted alphabetically"
name="FSSortAttachmentSpotsAlphabetically"
control_name="FSSortAttachmentSpotsAlphabetically"/>
+
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index a6794d68ac..1f935dcb15 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -3623,7 +3623,7 @@ Has actualizado una textura obtenida mediante bake de [RESOLUTION] para '[B
Has actualizado de manera local una textura obtenida mediante bake de [RESOLUTION] para '[BODYREGION]' después de [TIME] segundos.
- No se puede subir la textura.
+ No se puede subir la textura: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/default/xui/fr/floater_beacons.xml b/indra/newview/skins/default/xui/fr/floater_beacons.xml
index fb9c894ff5..215b41b5df 100644
--- a/indra/newview/skins/default/xui/fr/floater_beacons.xml
+++ b/indra/newview/skins/default/xui/fr/floater_beacons.xml
@@ -20,7 +20,7 @@
-
+
Montrer la direction :
diff --git a/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml
index c0bf186b60..9dfe297f1f 100644
--- a/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml
+++ b/indra/newview/skins/default/xui/fr/floater_scene_load_stats.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/fr/floater_translation_settings.xml b/indra/newview/skins/default/xui/fr/floater_translation_settings.xml
index eaeecd44ed..6808654c31 100644
--- a/indra/newview/skins/default/xui/fr/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/fr/floater_translation_settings.xml
@@ -33,7 +33,7 @@
-
+
[https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Guide]
Point final :
Clé Azure :
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index 2526e56e4c..4652703e30 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -3856,7 +3856,7 @@ Texture figée de [RESOLUTION] chargée pour [BODYREGION] au bout de [TIME] seco
Texture figée de [RESOLUTION] mise à jour localement pour [BODYREGION] au bout de [TIME] secondes.
- Chargement de la texture impossible.
+ Chargement de la texture impossible: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/default/xui/fr/panel_profile_pick.xml b/indra/newview/skins/default/xui/fr/panel_profile_pick.xml
index 3a9cdb3e8a..3ef06f0f79 100644
--- a/indra/newview/skins/default/xui/fr/panel_profile_pick.xml
+++ b/indra/newview/skins/default/xui/fr/panel_profile_pick.xml
@@ -18,8 +18,8 @@
Chargement en cours...
-
-
+
+
diff --git a/indra/newview/skins/default/xui/it/floater_360capture.xml b/indra/newview/skins/default/xui/it/floater_360capture.xml
index 4f218121be..e48600aafb 100644
--- a/indra/newview/skins/default/xui/it/floater_360capture.xml
+++ b/indra/newview/skins/default/xui/it/floater_360capture.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/indra/newview/skins/default/xui/it/floater_avatar_render_settings.xml b/indra/newview/skins/default/xui/it/floater_avatar_render_settings.xml
index 4738918e23..6653615c27 100644
--- a/indra/newview/skins/default/xui/it/floater_avatar_render_settings.xml
+++ b/indra/newview/skins/default/xui/it/floater_avatar_render_settings.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/indra/newview/skins/default/xui/it/floater_beacons.xml b/indra/newview/skins/default/xui/it/floater_beacons.xml
index 80dc19e317..1b8998be82 100644
--- a/indra/newview/skins/default/xui/it/floater_beacons.xml
+++ b/indra/newview/skins/default/xui/it/floater_beacons.xml
@@ -20,7 +20,7 @@
-
+
Mostra direzione:
diff --git a/indra/newview/skins/default/xui/it/floater_delete_pref_preset.xml b/indra/newview/skins/default/xui/it/floater_delete_pref_preset.xml
index 0e98b5f925..273c06f69e 100644
--- a/indra/newview/skins/default/xui/it/floater_delete_pref_preset.xml
+++ b/indra/newview/skins/default/xui/it/floater_delete_pref_preset.xml
@@ -1,4 +1,4 @@
-
+
Elimina Preset Grafica
diff --git a/indra/newview/skins/default/xui/it/floater_live_lsleditor.xml b/indra/newview/skins/default/xui/it/floater_live_lsleditor.xml
index 13c2fb1283..461f15c915 100644
--- a/indra/newview/skins/default/xui/it/floater_live_lsleditor.xml
+++ b/indra/newview/skins/default/xui/it/floater_live_lsleditor.xml
@@ -24,6 +24,9 @@
Caricamento in corso...
+
+ Oggetto: [SOURCE_OBJECT]
+
diff --git a/indra/newview/skins/default/xui/it/floater_load_pref_preset.xml b/indra/newview/skins/default/xui/it/floater_load_pref_preset.xml
index eb5865b311..74a7e68733 100644
--- a/indra/newview/skins/default/xui/it/floater_load_pref_preset.xml
+++ b/indra/newview/skins/default/xui/it/floater_load_pref_preset.xml
@@ -1,4 +1,4 @@
-
+
Carica Preset Grafica
diff --git a/indra/newview/skins/default/xui/it/floater_save_camera_preset.xml b/indra/newview/skins/default/xui/it/floater_save_camera_preset.xml
index 61a11638e4..410f46c0a6 100644
--- a/indra/newview/skins/default/xui/it/floater_save_camera_preset.xml
+++ b/indra/newview/skins/default/xui/it/floater_save_camera_preset.xml
@@ -1,4 +1,4 @@
-
+
Salva
diff --git a/indra/newview/skins/default/xui/it/floater_save_pref_preset.xml b/indra/newview/skins/default/xui/it/floater_save_pref_preset.xml
index 6733d08a16..fb3b72790d 100644
--- a/indra/newview/skins/default/xui/it/floater_save_pref_preset.xml
+++ b/indra/newview/skins/default/xui/it/floater_save_pref_preset.xml
@@ -1,4 +1,4 @@
-
+
Digita un nome per il preset o selezionane uno esistente.
diff --git a/indra/newview/skins/default/xui/it/floater_script_preview.xml b/indra/newview/skins/default/xui/it/floater_script_preview.xml
index 46e8d68b18..cbb27082f4 100644
--- a/indra/newview/skins/default/xui/it/floater_script_preview.xml
+++ b/indra/newview/skins/default/xui/it/floater_script_preview.xml
@@ -3,6 +3,9 @@
Script: [NAME]
+
+ Posizione: [PATH]
+
Descrizione:
diff --git a/indra/newview/skins/default/xui/it/floater_stats.xml b/indra/newview/skins/default/xui/it/floater_stats.xml
index c05db6e025..9982a8d3b9 100644
--- a/indra/newview/skins/default/xui/it/floater_stats.xml
+++ b/indra/newview/skins/default/xui/it/floater_stats.xml
@@ -30,22 +30,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/indra/newview/skins/default/xui/it/floater_translation_settings.xml b/indra/newview/skins/default/xui/it/floater_translation_settings.xml
index a123d1350a..01bd08ffbc 100644
--- a/indra/newview/skins/default/xui/it/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/it/floater_translation_settings.xml
@@ -32,7 +32,7 @@
Seleziona il servizio di traduzione:
-
+
[https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Setup]
@@ -113,7 +113,7 @@
Wybrany URL mediów, jeśli jest obecny
-
+
Mapowanie
diff --git a/indra/newview/skins/default/xui/pl/panel_topinfo_bar.xml b/indra/newview/skins/default/xui/pl/panel_topinfo_bar.xml
index f0eaff5f44..4a336e62a7 100644
--- a/indra/newview/skins/default/xui/pl/panel_topinfo_bar.xml
+++ b/indra/newview/skins/default/xui/pl/panel_topinfo_bar.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/indra/newview/skins/default/xui/pl/sidepanel_item_info.xml b/indra/newview/skins/default/xui/pl/sidepanel_item_info.xml
index 2e45656b35..5ef5c5d87b 100644
--- a/indra/newview/skins/default/xui/pl/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/pl/sidepanel_item_info.xml
@@ -50,10 +50,10 @@
-
+
Zezwolenia
-
+
Możesz:
@@ -74,7 +74,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/pl/sidepanel_task_info.xml b/indra/newview/skins/default/xui/pl/sidepanel_task_info.xml
index 67534ecc0a..84a3bbee2e 100644
--- a/indra/newview/skins/default/xui/pl/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/pl/sidepanel_task_info.xml
@@ -100,7 +100,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index e43ba1fbcd..eceae9e425 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -104,7 +104,7 @@ Wersja serwera głosu (Voice Server): [VOICE_VERSION]
Zmiana rozdzielczości...
- Pełna jasność
+ Superjasność
Trwa logowanie. [APP_NAME] może wydawać się zawieszony. Proszę czekać.
@@ -5086,6 +5086,12 @@ Raport o Nadużyciu
Nie można załadować obrazów większych niż [WIDTH]*[HEIGHT]
+
+ Nieprawidłowy format obrazu.
+
+
+ Plik jest pusty.
+
Maks. rozmiar zdjęcia stroju to [WIDTH]*[HEIGHT]. Przeskaluj lub użyj innego.
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index 317246adab..e3c00302b2 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -3414,7 +3414,7 @@ Você carregou uma textura com [RESOLUTION] para o(a) '[BODYREGION]' e
Você carregou uma textura com [RESOLUTION] para o(a) '[BODYREGION]' em [TIME] segundos.
- Não foi possível carregar textura.
+ Não foi possível carregar textura: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/default/xui/ru/floater_beacons.xml b/indra/newview/skins/default/xui/ru/floater_beacons.xml
index b1a0adfb72..32228fab75 100644
--- a/indra/newview/skins/default/xui/ru/floater_beacons.xml
+++ b/indra/newview/skins/default/xui/ru/floater_beacons.xml
@@ -20,7 +20,7 @@
-
+
Показать направление на:
diff --git a/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml
index d491033512..6f52136f20 100644
--- a/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml
+++ b/indra/newview/skins/default/xui/ru/floater_scene_load_stats.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/indra/newview/skins/default/xui/ru/floater_translation_settings.xml b/indra/newview/skins/default/xui/ru/floater_translation_settings.xml
index c15ff3afa8..401114a4cf 100644
--- a/indra/newview/skins/default/xui/ru/floater_translation_settings.xml
+++ b/indra/newview/skins/default/xui/ru/floater_translation_settings.xml
@@ -49,7 +49,7 @@
-
+
[https://learn.microsoft.com/en-us/azure/cognitive-services/translator/create-translator-resource Установка]
diff --git a/indra/newview/skins/default/xui/ru/notifications.xml b/indra/newview/skins/default/xui/ru/notifications.xml
index 61d5f747a6..f55b3cb269 100644
--- a/indra/newview/skins/default/xui/ru/notifications.xml
+++ b/indra/newview/skins/default/xui/ru/notifications.xml
@@ -3790,7 +3790,7 @@ https://wiki.firestormviewer.org/fs_voice
Вы локально обновили готовую текстуру [RESOLUTION] для "[BODYREGION]" через [TIME] сек.
- Невозможно загрузить текстуру.
+ Невозможно загрузить текстуру: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/default/xui/ru/panel_profile_pick.xml b/indra/newview/skins/default/xui/ru/panel_profile_pick.xml
index 1e515aee83..66f0e59a56 100644
--- a/indra/newview/skins/default/xui/ru/panel_profile_pick.xml
+++ b/indra/newview/skins/default/xui/ru/panel_profile_pick.xml
@@ -10,8 +10,8 @@
Локация:
Загрузка...
-
-
+
+
diff --git a/indra/newview/skins/default/xui/ru/sidepanel_item_info.xml b/indra/newview/skins/default/xui/ru/sidepanel_item_info.xml
index 02016eaa4f..d0faf49975 100644
--- a/indra/newview/skins/default/xui/ru/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/ru/sidepanel_item_info.xml
@@ -57,10 +57,10 @@
-
+
Разрешения
-
+
Вы можете:
diff --git a/indra/newview/skins/default/xui/tr/notifications.xml b/indra/newview/skins/default/xui/tr/notifications.xml
index 869da6cf74..b08faee9d1 100644
--- a/indra/newview/skins/default/xui/tr/notifications.xml
+++ b/indra/newview/skins/default/xui/tr/notifications.xml
@@ -3524,7 +3524,7 @@ Sesli iletişim kullanılamayacak.
'[BODYREGION]' için [RESOLUTION] çözünürlükte kaydedilmiş bir dokuyu [TIME] saniye sonra yerel olarak güncellediniz.
- Doku karşıya yüklenemiyor.
+ Doku karşıya yüklenemiyor: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/default/xui/zh/notifications.xml b/indra/newview/skins/default/xui/zh/notifications.xml
index 22ff3fd673..cff4998360 100644
--- a/indra/newview/skins/default/xui/zh/notifications.xml
+++ b/indra/newview/skins/default/xui/zh/notifications.xml
@@ -3387,7 +3387,7 @@ SHA1 指紋:[MD5_DIGEST]
你在 [TIME] 秒鐘後在本地為 '[BODYREGION]' 更新了一個 [RESOLUTION] 的定貌材質。
- 無法上傳質料。
+ 無法上傳質料: '[NAME]'
[REASON]
diff --git a/indra/newview/skins/starlight/xui/en/floater_tools.xml b/indra/newview/skins/starlight/xui/en/floater_tools.xml
index f31e109fe8..c1fb8f780e 100644
--- a/indra/newview/skins/starlight/xui/en/floater_tools.xml
+++ b/indra/newview/skins/starlight/xui/en/floater_tools.xml
@@ -3236,8 +3236,10 @@ Low ↔ Lwst
+
+
+