phoenix-firestorm/indra/newview/llpanelface.cpp

5212 lines
184 KiB
C++
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/**
* @file llpanelface.cpp
* @brief Panel in the tools floater for editing face textures, colors, etc.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
// file include
#include "llpanelface.h"
// library includes
#include "llcalc.h"
#include "llerror.h"
#include "llrect.h"
#include "llstring.h"
#include "llfontgl.h"
// project includes
#include "llagent.h"
#include "llagentdata.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcolorswatch.h"
#include "llcombobox.h"
#include "lldrawpoolbump.h"
#include "llface.h"
#include "llgltfmateriallist.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h" // gInventory
#include "llinventorymodelbackgroundfetch.h"
#include "llfloatermediasettings.h"
#include "llfloaterreg.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 "llradiogroup.h"
#include "llresmgr.h"
#include "llselectmgr.h"
#include "llspinctrl.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 "llviewercontrol.h"
#include "llviewermedia.h"
#include "llviewerobject.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llvovolume.h"
#include "lluictrlfactory.h"
#include "llpluginclassmedia.h"
#include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI
#include "llagent.h"
#include "llfilesystem.h"
#include "llviewerassetupload.h"
#include "llviewermenufile.h"
#include "llsd.h"
#include "llsdutil.h"
#include "llsdserialize.h"
#include "llinventorymodel.h"
using namespace std::literals;
LLPanelFace::Selection LLPanelFace::sMaterialOverrideSelection;
//
// Constant definitions for comboboxes
// Must match the commbobox definitions in panel_tools_texture.xml
//
const S32 MATMEDIA_MATERIAL = 0; // Material
const S32 MATMEDIA_PBR = 1; // PBR
const S32 MATMEDIA_MEDIA = 2; // Media
const S32 MATTYPE_DIFFUSE = 0; // Diffuse material texture
const S32 MATTYPE_NORMAL = 1; // Normal map
const S32 MATTYPE_SPECULAR = 2; // Specular map
const S32 ALPHAMODE_MASK = 2; // Alpha masking mode
const S32 BUMPY_TEXTURE = 18; // use supplied normal map
const S32 SHINY_TEXTURE = 4; // use supplied specular map
const S32 PBRTYPE_RENDER_MATERIAL_ID = 0; // Render Material ID
const S32 PBRTYPE_BASE_COLOR = 1; // PBR Base Color
const S32 PBRTYPE_NORMAL = 2; // PBR Normal
const S32 PBRTYPE_METALLIC_ROUGHNESS = 3; // PBR Metallic
const S32 PBRTYPE_EMISSIVE = 4; // PBR Emissive
LLGLTFMaterial::TextureInfo texture_info_from_pbrtype(S32 pbr_type)
{
switch (pbr_type)
{
case PBRTYPE_BASE_COLOR:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR;
break;
case PBRTYPE_NORMAL:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL;
break;
case PBRTYPE_METALLIC_ROUGHNESS:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS;
break;
case PBRTYPE_EMISSIVE:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE;
break;
default:
return LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT;
break;
}
}
void LLPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func)
{
struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor
{
LLSelectedTEGLTFMaterialFunctor(std::function<void(LLGLTFMaterial*)> 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<void(LLGLTFMaterial*)> mFunc;
} select_func(func);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func);
}
template<typename T>
void readSelectedGLTFMaterial(std::function<T(const LLGLTFMaterial*)> func, T& value, bool& identical, bool has_tolerance, T tolerance)
{
struct LLSelectedTEGetGLTFMaterialFunctor : public LLSelectedTEGetFunctor<T>
{
LLSelectedTEGetGLTFMaterialFunctor(std::function<T(const LLGLTFMaterial*)> 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<T(const LLGLTFMaterial*)> mFunc;
} select_func(func);
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&select_func, value, has_tolerance, tolerance);
}
BOOST_STATIC_ASSERT(MATTYPE_DIFFUSE == LLRender::DIFFUSE_MAP && MATTYPE_NORMAL == LLRender::NORMAL_MAP && MATTYPE_SPECULAR == LLRender::SPECULAR_MAP);
//
// "Use texture" label for normal/specular type comboboxes
// Filled in at initialization from translated strings
//
std::string USE_TEXTURE;
LLRender::eTexIndex LLPanelFace::getTextureChannelToEdit()
{
LLRender::eTexIndex channel_to_edit = LLRender::DIFFUSE_MAP;
if (mComboMatMedia)
{
U32 matmedia_selection = mComboMatMedia->getCurrentIndex();
if (matmedia_selection == MATMEDIA_MATERIAL)
{
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
channel_to_edit = (LLRender::eTexIndex)radio_mat_type->getSelectedIndex();
}
if (matmedia_selection == MATMEDIA_PBR)
{
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_pbr_type");
channel_to_edit = (LLRender::eTexIndex)radio_mat_type->getSelectedIndex();
}
}
channel_to_edit = (channel_to_edit == LLRender::NORMAL_MAP) ? (getCurrentNormalMap().isNull() ? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit;
channel_to_edit = (channel_to_edit == LLRender::SPECULAR_MAP) ? (getCurrentSpecularMap().isNull() ? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit;
return channel_to_edit;
}
LLRender::eTexIndex LLPanelFace::getTextureDropChannel()
{
if (mComboMatMedia && mComboMatMedia->getCurrentIndex() == MATMEDIA_MATERIAL)
{
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
return LLRender::eTexIndex(radio_mat_type->getSelectedIndex());
}
return LLRender::eTexIndex(MATTYPE_DIFFUSE);
}
// Things the UI provides...
//
LLUUID LLPanelFace::getCurrentNormalMap() { return getChild<LLTextureCtrl>("bumpytexture control")->getImageAssetID(); }
LLUUID LLPanelFace::getCurrentSpecularMap() { return getChild<LLTextureCtrl>("shinytexture control")->getImageAssetID(); }
U32 LLPanelFace::getCurrentShininess() { return getChild<LLComboBox>("combobox shininess")->getCurrentIndex(); }
U32 LLPanelFace::getCurrentBumpiness() { return getChild<LLComboBox>("combobox bumpiness")->getCurrentIndex(); }
U8 LLPanelFace::getCurrentDiffuseAlphaMode() { return (U8)getChild<LLComboBox>("combobox alphamode")->getCurrentIndex(); }
U8 LLPanelFace::getCurrentAlphaMaskCutoff() { return (U8)getChild<LLUICtrl>("maskcutoff")->getValue().asInteger(); }
U8 LLPanelFace::getCurrentEnvIntensity() { return (U8)getChild<LLUICtrl>("environment")->getValue().asInteger(); }
U8 LLPanelFace::getCurrentGlossiness() { return (U8)getChild<LLUICtrl>("glossiness")->getValue().asInteger(); }
F32 LLPanelFace::getCurrentBumpyRot() { return getChild<LLUICtrl>("bumpyRot")->getValue().asReal(); }
F32 LLPanelFace::getCurrentBumpyScaleU() { return getChild<LLUICtrl>("bumpyScaleU")->getValue().asReal(); }
F32 LLPanelFace::getCurrentBumpyScaleV() { return getChild<LLUICtrl>("bumpyScaleV")->getValue().asReal(); }
F32 LLPanelFace::getCurrentBumpyOffsetU() { return getChild<LLUICtrl>("bumpyOffsetU")->getValue().asReal(); }
F32 LLPanelFace::getCurrentBumpyOffsetV() { return getChild<LLUICtrl>("bumpyOffsetV")->getValue().asReal(); }
F32 LLPanelFace::getCurrentShinyRot() { return getChild<LLUICtrl>("shinyRot")->getValue().asReal(); }
F32 LLPanelFace::getCurrentShinyScaleU() { return getChild<LLUICtrl>("shinyScaleU")->getValue().asReal(); }
F32 LLPanelFace::getCurrentShinyScaleV() { return getChild<LLUICtrl>("shinyScaleV")->getValue().asReal(); }
F32 LLPanelFace::getCurrentShinyOffsetU() { return getChild<LLUICtrl>("shinyOffsetU")->getValue().asReal(); }
F32 LLPanelFace::getCurrentShinyOffsetV() { return getChild<LLUICtrl>("shinyOffsetV")->getValue().asReal(); }
//
// Methods
//
BOOL LLPanelFace::postBuild()
{
childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this);
childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this);
childSetCommitCallback("combobox alphamode",&LLPanelFace::onCommitAlphaMode,this);
childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureScaleX, this);
childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureScaleY, this);
childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureRot, this);
childSetCommitCallback("rptctrl",&LLPanelFace::onCommitRepeatsPerMeter, this);
childSetCommitCallback("checkbox planar align",&LLPanelFace::onCommitPlanarAlign, this);
childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureOffsetX, this);
childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureOffsetY, this);
childSetCommitCallback("bumpyScaleU",&LLPanelFace::onCommitMaterialBumpyScaleX, this);
childSetCommitCallback("bumpyScaleV",&LLPanelFace::onCommitMaterialBumpyScaleY, this);
childSetCommitCallback("bumpyRot",&LLPanelFace::onCommitMaterialBumpyRot, this);
childSetCommitCallback("bumpyOffsetU",&LLPanelFace::onCommitMaterialBumpyOffsetX, this);
childSetCommitCallback("bumpyOffsetV",&LLPanelFace::onCommitMaterialBumpyOffsetY, this);
childSetCommitCallback("shinyScaleU",&LLPanelFace::onCommitMaterialShinyScaleX, this);
childSetCommitCallback("shinyScaleV",&LLPanelFace::onCommitMaterialShinyScaleY, this);
childSetCommitCallback("shinyRot",&LLPanelFace::onCommitMaterialShinyRot, this);
childSetCommitCallback("shinyOffsetU",&LLPanelFace::onCommitMaterialShinyOffsetX, this);
childSetCommitCallback("shinyOffsetV",&LLPanelFace::onCommitMaterialShinyOffsetY, this);
childSetCommitCallback("glossiness",&LLPanelFace::onCommitMaterialGloss, this);
childSetCommitCallback("environment",&LLPanelFace::onCommitMaterialEnv, this);
childSetCommitCallback("maskcutoff",&LLPanelFace::onCommitMaterialMaskCutoff, this);
childSetCommitCallback("add_media", &LLPanelFace::onClickBtnAddMedia, this);
childSetCommitCallback("delete_media", &LLPanelFace::onClickBtnDeleteMedia, this);
getChild<LLUICtrl>("gltfTextureScaleU")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureScaleU, this, _1), nullptr);
getChild<LLUICtrl>("gltfTextureScaleV")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureScaleV, this, _1), nullptr);
getChild<LLUICtrl>("gltfTextureRotation")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFRotation, this, _1), nullptr);
getChild<LLUICtrl>("gltfTextureOffsetU")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureOffsetU, this, _1), nullptr);
getChild<LLUICtrl>("gltfTextureOffsetV")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureOffsetV, this, _1), nullptr);
LLGLTFMaterialList::addSelectionUpdateCallback(&LLPanelFace::onMaterialOverrideReceived);
sMaterialOverrideSelection.connect();
childSetAction("button align",&LLPanelFace::onClickAutoFix,this);
childSetAction("button align textures", &LLPanelFace::onAlignTexture, this);
childSetAction("pbr_from_inventory", &LLPanelFace::onClickBtnLoadInvPBR, this);
childSetAction("edit_selected_pbr", &LLPanelFace::onClickBtnEditPBR, this);
childSetAction("save_selected_pbr", &LLPanelFace::onClickBtnSavePBR, this);
LLTextureCtrl* mTextureCtrl;
LLTextureCtrl* mShinyTextureCtrl;
LLTextureCtrl* mBumpyTextureCtrl;
LLColorSwatchCtrl* mColorSwatch;
LLColorSwatchCtrl* mShinyColorSwatch;
LLComboBox* mComboTexGen;
LLCheckBoxCtrl *mCheckFullbright;
LLTextBox* mLabelColorTransp;
LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha
LLSpinCtrl* mCtrlGlow;
setMouseOpaque(FALSE);
LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
if (pbr_ctrl)
{
pbr_ctrl->setDefaultImageAssetID(LLUUID::null);
pbr_ctrl->setBlankImageAssetID(LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID);
pbr_ctrl->setCommitCallback(boost::bind(&LLPanelFace::onCommitPbr, this, _2));
pbr_ctrl->setOnCancelCallback(boost::bind(&LLPanelFace::onCancelPbr, this, _2));
pbr_ctrl->setOnSelectCallback(boost::bind(&LLPanelFace::onSelectPbr, this, _2));
pbr_ctrl->setDragCallback(boost::bind(&LLPanelFace::onDragPbr, this, _2));
pbr_ctrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onPbrSelectionChanged, this, _1));
pbr_ctrl->setOnCloseCallback(boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2));
pbr_ctrl->setFollowsTop();
pbr_ctrl->setFollowsLeft();
pbr_ctrl->setImmediateFilterPermMask(PERM_NONE);
pbr_ctrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
pbr_ctrl->setBakeTextureEnabled(false);
pbr_ctrl->setInventoryPickType(LLTextureCtrl::PICK_MATERIAL);
}
mTextureCtrl = getChild<LLTextureCtrl>("texture control");
if(mTextureCtrl)
{
mTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectTexture" )));
mTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitTexture, this, _2) );
mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) );
mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) );
mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
mTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
mTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) );
mTextureCtrl->setFollowsTop();
mTextureCtrl->setFollowsLeft();
mTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
}
mShinyTextureCtrl = getChild<LLTextureCtrl>("shinytexture control");
if(mShinyTextureCtrl)
{
mShinyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectSpecularTexture" )));
mShinyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitSpecularTexture, this, _2) );
mShinyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelSpecularTexture, this, _2) );
mShinyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectSpecularTexture, this, _2) );
mShinyTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) );
mShinyTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
mShinyTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
mShinyTextureCtrl->setFollowsTop();
mShinyTextureCtrl->setFollowsLeft();
mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
mShinyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
}
mBumpyTextureCtrl = getChild<LLTextureCtrl>("bumpytexture control");
if(mBumpyTextureCtrl)
{
mBumpyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectNormalTexture" )));
mBumpyTextureCtrl->setBlankImageAssetID(LLUUID( gSavedSettings.getString( "DefaultBlankNormalTexture" )));
mBumpyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitNormalTexture, this, _2) );
mBumpyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelNormalTexture, this, _2) );
mBumpyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectNormalTexture, this, _2) );
mBumpyTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) );
mBumpyTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
mBumpyTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
mBumpyTextureCtrl->setFollowsTop();
mBumpyTextureCtrl->setFollowsLeft();
mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
mBumpyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
}
mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
if(mColorSwatch)
{
mColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::onCommitColor, this, _2));
mColorSwatch->setOnCancelCallback(boost::bind(&LLPanelFace::onCancelColor, this, _2));
mColorSwatch->setOnSelectCallback(boost::bind(&LLPanelFace::onSelectColor, this, _2));
mColorSwatch->setFollowsTop();
mColorSwatch->setFollowsLeft();
mColorSwatch->setCanApplyImmediately(TRUE);
}
mShinyColorSwatch = getChild<LLColorSwatchCtrl>("shinycolorswatch");
if(mShinyColorSwatch)
{
mShinyColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::onCommitShinyColor, this, _2));
mShinyColorSwatch->setOnCancelCallback(boost::bind(&LLPanelFace::onCancelShinyColor, this, _2));
mShinyColorSwatch->setOnSelectCallback(boost::bind(&LLPanelFace::onSelectShinyColor, this, _2));
mShinyColorSwatch->setFollowsTop();
mShinyColorSwatch->setFollowsLeft();
mShinyColorSwatch->setCanApplyImmediately(TRUE);
}
mLabelColorTransp = getChild<LLTextBox>("color trans");
if(mLabelColorTransp)
{
mLabelColorTransp->setFollowsTop();
mLabelColorTransp->setFollowsLeft();
}
mCtrlColorTransp = getChild<LLSpinCtrl>("ColorTrans");
if(mCtrlColorTransp)
{
mCtrlColorTransp->setCommitCallback(boost::bind(&LLPanelFace::onCommitAlpha, this, _2));
mCtrlColorTransp->setPrecision(0);
mCtrlColorTransp->setFollowsTop();
mCtrlColorTransp->setFollowsLeft();
}
mCheckFullbright = getChild<LLCheckBoxCtrl>("checkbox fullbright");
if (mCheckFullbright)
{
mCheckFullbright->setCommitCallback(LLPanelFace::onCommitFullbright, this);
}
mComboTexGen = getChild<LLComboBox>("combobox texgen");
if(mComboTexGen)
{
mComboTexGen->setCommitCallback(LLPanelFace::onCommitTexGen, this);
mComboTexGen->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP);
}
mComboMatMedia = getChild<LLComboBox>("combobox matmedia");
if(mComboMatMedia)
{
mComboMatMedia->setCommitCallback(LLPanelFace::onCommitMaterialsMedia,this);
mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL);
}
LLRadioGroup* radio_mat_type = findChild<LLRadioGroup>("radio_material_type");
if(radio_mat_type)
{
radio_mat_type->setCommitCallback(LLPanelFace::onCommitMaterialType, this);
radio_mat_type->selectNthItem(MATTYPE_DIFFUSE);
}
LLRadioGroup* radio_pbr_type = findChild<LLRadioGroup>("radio_pbr_type");
if (radio_pbr_type)
{
radio_pbr_type->setCommitCallback(LLPanelFace::onCommitPbrType, this);
radio_pbr_type->selectNthItem(PBRTYPE_RENDER_MATERIAL_ID);
}
mCtrlGlow = getChild<LLSpinCtrl>("glow");
if(mCtrlGlow)
{
mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this);
}
mMenuClipboardColor = getChild<LLMenuButton>("clipboard_color_params_btn");
mMenuClipboardTexture = getChild<LLMenuButton>("clipboard_texture_params_btn");
mTitleMedia = getChild<LLMediaCtrl>("title_media");
mTitleMediaText = getChild<LLTextBox>("media_info");
clearCtrls();
return TRUE;
}
LLPanelFace::LLPanelFace()
: LLPanel(),
mIsAlpha(false),
mComboMatMedia(NULL),
mTitleMedia(NULL),
mTitleMediaText(NULL),
mNeedMediaTitle(true)
{
USE_TEXTURE = LLTrans::getString("use_texture");
mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2));
mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2));
}
LLPanelFace::~LLPanelFace()
{
unloadMedia();
}
void LLPanelFace::draw()
{
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();
if (sMaterialOverrideSelection.update())
{
setMaterialOverridesFromSelection();
}
}
void LLPanelFace::sendTexture()
{
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("texture control");
if(!mTextureCtrl) return;
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))
{
// need to refresh value in texture ctrl
refresh();
}
}
}
void LLPanelFace::sendBump(U32 bumpiness)
{
LLTextureCtrl* bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
if (bumpiness < BUMPY_TEXTURE)
{
LL_DEBUGS("Materials") << "clearing bumptexture control" << LL_ENDL;
bumpytexture_ctrl->clear();
bumpytexture_ctrl->setImageAssetID(LLUUID());
}
updateBumpyControls(bumpiness == BUMPY_TEXTURE, true);
LLUUID current_normal_map = bumpytexture_ctrl->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, bumpytexture_ctrl->getImageItemID() );
}
void LLPanelFace::sendTexGen()
{
LLComboBox* mComboTexGen = getChild<LLComboBox>("combobox texgen");
if(!mComboTexGen)return;
U8 tex_gen = (U8) mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT;
LLSelectMgr::getInstance()->selectionSetTexGen( tex_gen );
}
void LLPanelFace::sendShiny(U32 shininess)
{
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
if (shininess < SHINY_TEXTURE)
{
texture_ctrl->clear();
texture_ctrl->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, texture_ctrl->getImageItemID() );
updateShinyControls(!specmap.isNull(), true);
}
void LLPanelFace::sendFullbright()
{
LLCheckBoxCtrl* mCheckFullbright = getChild<LLCheckBoxCtrl>("checkbox fullbright");
if(!mCheckFullbright)return;
U8 fullbright = mCheckFullbright->get() ? TEM_FULLBRIGHT_MASK : 0;
LLSelectMgr::getInstance()->selectionSetFullbright( fullbright );
}
void LLPanelFace::sendColor()
{
LLColorSwatchCtrl* mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
if(!mColorSwatch)return;
LLColor4 color = mColorSwatch->get();
LLSelectMgr::getInstance()->selectionSetColorOnly( color );
}
void LLPanelFace::sendAlpha()
{
LLSpinCtrl* mCtrlColorTransp = getChild<LLSpinCtrl>("ColorTrans");
if(!mCtrlColorTransp)return;
F32 alpha = (100.f - mCtrlColorTransp->get()) / 100.f;
LLSelectMgr::getInstance()->selectionSetAlphaOnly( alpha );
}
void LLPanelFace::sendGlow()
{
LLSpinCtrl* mCtrlGlow = getChild<LLSpinCtrl>("glow");
llassert(mCtrlGlow);
if (mCtrlGlow)
{
F32 glow = mCtrlGlow->get();
LLSelectMgr::getInstance()->selectionSetGlow( glow );
}
}
struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor
{
LLPanelFaceSetTEFunctor(LLPanelFace* panel) : mPanel(panel) {}
virtual bool apply(LLViewerObject* object, S32 te)
{
BOOL valid;
F32 value;
std::string prefix;
// Effectively the same as MATMEDIA_PBR sans using different radio,
// separate for the sake of clarity
LLRadioGroup * radio_mat_type = mPanel->getChild<LLRadioGroup>("radio_material_type");
switch (radio_mat_type->getSelectedIndex())
{
case MATTYPE_DIFFUSE:
prefix = "Tex";
break;
case MATTYPE_NORMAL:
prefix = "bumpy";
break;
case MATTYPE_SPECULAR:
prefix = "shiny";
break;
}
LLSpinCtrl * ctrlTexScaleS = mPanel->getChild<LLSpinCtrl>(prefix + "ScaleU");
LLSpinCtrl * ctrlTexScaleT = mPanel->getChild<LLSpinCtrl>(prefix + "ScaleV");
LLSpinCtrl * ctrlTexOffsetS = mPanel->getChild<LLSpinCtrl>(prefix + "OffsetU");
LLSpinCtrl * ctrlTexOffsetT = mPanel->getChild<LLSpinCtrl>(prefix + "OffsetV");
LLSpinCtrl * ctrlTexRotation = mPanel->getChild<LLSpinCtrl>(prefix + "Rot");
LLComboBox* comboTexGen = mPanel->getChild<LLComboBox>("combobox texgen");
LLCheckBoxCtrl* cb_planar_align = mPanel->getChild<LLCheckBoxCtrl>("checkbox planar align");
bool align_planar = (cb_planar_align && cb_planar_align->get());
llassert(comboTexGen);
llassert(object);
if (ctrlTexScaleS)
{
valid = !ctrlTexScaleS->getTentative(); // || !checkFlipScaleS->getTentative();
if (valid || align_planar)
{
value = ctrlTexScaleS->get();
if (comboTexGen &&
comboTexGen->getCurrentIndex() == 1)
{
value *= 0.5f;
}
object->setTEScaleS( te, value );
if (align_planar)
{
LLPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, value, te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, value, te, object->getID());
}
}
}
if (ctrlTexScaleT)
{
valid = !ctrlTexScaleT->getTentative(); // || !checkFlipScaleT->getTentative();
if (valid || align_planar)
{
value = ctrlTexScaleT->get();
//if( checkFlipScaleT->get() )
//{
// value = -value;
//}
if (comboTexGen &&
comboTexGen->getCurrentIndex() == 1)
{
value *= 0.5f;
}
object->setTEScaleT( te, value );
if (align_planar)
{
LLPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, value, te, object->getID());
LLPanelFace::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)
{
LLPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, value, te, object->getID());
LLPanelFace::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)
{
LLPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, value, te, object->getID());
LLPanelFace::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)
{
LLPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, value, te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, value, te, object->getID());
}
}
}
return true;
}
private:
LLPanelFace* mPanel;
};
// Functor that aligns a face to mCenterFace
struct LLPanelFaceSetAlignedTEFunctor : public LLSelectedTEFunctor
{
LLPanelFaceSetAlignedTEFunctor(LLPanelFace* 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);
LLPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
}
}
if (!set_aligned)
{
LLPanelFaceSetTEFunctor setfunc(mPanel);
setfunc.apply(object, te);
}
return true;
}
private:
LLPanelFace* mPanel;
LLFace* mCenterFace;
};
struct LLPanelFaceSetAlignedConcreteTEFunctor : public LLSelectedTEFunctor
{
LLPanelFaceSetAlignedConcreteTEFunctor(LLPanelFace* 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:
LLPanelFace::LLSelectedTEMaterial::setNormalRotation(mPanel, uv_rot, te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setNormalRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
break;
case LLRender::SPECULAR_MAP:
LLPanelFace::LLSelectedTEMaterial::setSpecularRotation(mPanel, uv_rot, te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularOffsetX(mPanel, uv_offset.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularOffsetY(mPanel, uv_offset.mV[VY], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatX(mPanel, uv_scale.mV[VX], te, object->getID());
LLPanelFace::LLSelectedTEMaterial::setSpecularRepeatY(mPanel, uv_scale.mV[VY], te, object->getID());
break;
default: /*make compiler happy*/
break;
}
}
}
return true;
}
private:
LLPanelFace* mPanel;
LLFace* mChefFace;
LLRender::eTexIndex mMap;
};
// Functor that tests if a face is aligned to mCenterFace
struct LLPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor
{
LLPanelFaceGetIsAlignedTEFunctor(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 LLPanelFaceSendFunctor : public LLSelectedObjectFunctor
{
virtual bool apply(LLViewerObject* object)
{
object->sendTEUpdate();
return true;
}
};
void LLPanelFace::sendTextureInfo()
{
if ((bool)childGetValue("checkbox planar align").asBoolean())
{
LLFace* last_face = NULL;
bool identical_face =false;
LLSelectedTE::getFace(last_face, identical_face);
LLPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
else
{
LLPanelFaceSetTEFunctor setfunc(this);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
LLPanelFaceSendFunctor sendfunc;
LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc);
}
void LLPanelFace::alignTestureLayer()
{
LLFace* last_face = NULL;
bool identical_face = false;
LLSelectedTE::getFace(last_face, identical_face);
LLRadioGroup * radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
LLPanelFaceSetAlignedConcreteTEFunctor setfunc(this, last_face, static_cast<LLRender::eTexIndex>(radio_mat_type->getSelectedIndex()));
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
void LLPanelFace::getState()
{
updateUI();
}
void LLPanelFace::updateUI(bool force_set_values /*false*/)
{ //set state of UI to match state of texture entry(ies) (calls setEnabled, setValue, etc, but NOT setVisible)
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
if (objectp
&& objectp->getPCode() == LL_PCODE_VOLUME
&& objectp->permModify())
{
BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced();
bool has_pbr_material;
updateUIGLTF(objectp, has_pbr_material, force_set_values);
const bool has_material = !has_pbr_material;
// only turn on auto-adjust button if there is a media renderer and the media is loaded
childSetEnabled("button align", editable);
if (mComboMatMedia->getCurrentIndex() < MATMEDIA_MATERIAL)
{
// When selecting an object with a pbr and UI combo is not set,
// set to pbr option, otherwise to a texture (material)
if (has_pbr_material)
{
mComboMatMedia->selectNthItem(MATMEDIA_PBR);
}
else
{
mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL);
}
}
mComboMatMedia->setEnabled(editable);
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");

if (radio_mat_type->getSelectedIndex() < MATTYPE_DIFFUSE)
{
radio_mat_type->selectNthItem(MATTYPE_DIFFUSE);
}
radio_mat_type->setEnabled(editable);
LLRadioGroup* radio_pbr_type = getChild<LLRadioGroup>("radio_pbr_type");
if (radio_pbr_type->getSelectedIndex() < PBRTYPE_RENDER_MATERIAL_ID)
{
radio_pbr_type->selectNthItem(PBRTYPE_RENDER_MATERIAL_ID);
}
radio_pbr_type->setEnabled(editable);
const bool pbr_selected = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR;
const bool texture_info_selected = pbr_selected && radio_pbr_type->getSelectedIndex() != PBRTYPE_RENDER_MATERIAL_ID;
getChildView("checkbox_sync_settings")->setEnabled(editable);
childSetValue("checkbox_sync_settings", gSavedSettings.getBOOL("SyncMaterialSettings"));
updateVisibility();
// *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;
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control");
LLTextureCtrl* shinytexture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
LLTextureCtrl* bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
LLUUID id;
LLUUID normmap_id;
LLUUID specmap_id;
// Color swatch
{
getChildView("color label")->setEnabled(editable);
}
LLColorSwatchCtrl* color_swatch = findChild<LLColorSwatchCtrl>("colorswatch");
LLColor4 color = LLColor4::white;
bool identical_color = false;
if (color_swatch)
{
LLSelectedTE::getColor(color, identical_color);
LLColor4 prev_color = color_swatch->get();
color_swatch->setOriginal(color);
color_swatch->set(color, force_set_values || (prev_color != color) || !editable);
color_swatch->setValid(editable && !has_pbr_material);
color_swatch->setEnabled( editable && !has_pbr_material);
color_swatch->setCanApplyImmediately( editable && !has_pbr_material);
}
// Color transparency
getChildView("color trans")->setEnabled(editable);
F32 transparency = (1.f - color.mV[VALPHA]) * 100.f;
getChild<LLUICtrl>("ColorTrans")->setValue(editable ? transparency : 0);
getChildView("ColorTrans")->setEnabled(editable && has_material);
// Specular map
LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec);
U8 shiny = 0;
bool identical_shiny = false;
// Shiny
LLSelectedTE::getShiny(shiny, identical_shiny);
identical = identical && identical_shiny;
shiny = specmap_id.isNull() ? shiny : SHINY_TEXTURE;
LLCtrlSelectionInterface* combobox_shininess = childGetSelectionInterface("combobox shininess");
if (combobox_shininess)
{
combobox_shininess->selectNthItem((S32)shiny);
}
getChildView("label shininess")->setEnabled(editable);
getChildView("combobox shininess")->setEnabled(editable);
getChildView("label glossiness")->setEnabled(editable);
getChildView("glossiness")->setEnabled(editable);
getChildView("label environment")->setEnabled(editable);
getChildView("environment")->setEnabled(editable);
getChildView("label shinycolor")->setEnabled(editable);
getChild<LLUICtrl>("combobox shininess")->setTentative(!identical_spec);
getChild<LLUICtrl>("glossiness")->setTentative(!identical_spec);
getChild<LLUICtrl>("environment")->setTentative(!identical_spec);
getChild<LLUICtrl>("shinycolorswatch")->setTentative(!identical_spec);
LLColorSwatchCtrl* mShinyColorSwatch = getChild<LLColorSwatchCtrl>("shinycolorswatch");
if (mShinyColorSwatch)
{
mShinyColorSwatch->setValid(editable);
mShinyColorSwatch->setEnabled( editable );
mShinyColorSwatch->setCanApplyImmediately( editable );
}
U8 bumpy = 0;
// Bumpy
{
bool identical_bumpy = false;
LLSelectedTE::getBumpmap(bumpy,identical_bumpy);
LLUUID norm_map_id = getCurrentNormalMap();
LLCtrlSelectionInterface* combobox_bumpiness = childGetSelectionInterface("combobox bumpiness");
bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
if (combobox_bumpiness)
{
combobox_bumpiness->selectNthItem((S32)bumpy);
}
else
{
LL_WARNS() << "failed childGetSelectionInterface for 'combobox bumpiness'" << LL_ENDL;
}
getChildView("combobox bumpiness")->setEnabled(editable);
getChild<LLUICtrl>("combobox bumpiness")->setTentative(!identical_bumpy);
getChildView("label bumpiness")->setEnabled(editable);
}
// Texture
{
LLSelectedTE::getTexId(id,identical_diffuse);
// Normal map
LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm);
mIsAlpha = FALSE;
LLGLenum image_format = GL_RGB;
bool identical_image_format = false;
LLSelectedTE::getImageFormat(image_format, identical_image_format);
mIsAlpha = FALSE;
switch (image_format)
{
case GL_RGBA:
case GL_ALPHA:
{
mIsAlpha = TRUE;
}
break;
case GL_RGB: break;
default:
{
LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
}
break;
}
if (LLViewerMedia::getInstance()->textureHasMedia(id))
{
getChildView("button align")->setEnabled(editable);
}
// Diffuse Alpha Mode
// Init to the default that is appropriate for the alpha content of the asset
//
U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
bool identical_alpha_mode = false;
// See if that's been overridden by a material setting for same...
//
LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha);
LLCtrlSelectionInterface* combobox_alphamode = childGetSelectionInterface("combobox alphamode");
if (combobox_alphamode)
{
//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;
combobox_alphamode->selectNthItem(alpha_mode);
}
else
{
LL_WARNS() << "failed childGetSelectionInterface for 'combobox alphamode'" << LL_ENDL;
}
updateAlphaControls();
if (texture_ctrl)
{
if (identical_diffuse)
{
texture_ctrl->setTentative(FALSE);
texture_ctrl->setEnabled(editable && !has_pbr_material);
texture_ctrl->setImageAssetID(id);
getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f && !has_pbr_material);
getChildView("label alphamode")->setEnabled(editable && mIsAlpha && !has_pbr_material);
getChildView("maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
texture_ctrl->setBakeTextureEnabled(TRUE);
}
else if (id.isNull())
{
// None selected
texture_ctrl->setTentative(FALSE);
texture_ctrl->setEnabled(FALSE);
texture_ctrl->setImageAssetID(LLUUID::null);
getChildView("combobox alphamode")->setEnabled(FALSE);
getChildView("label alphamode")->setEnabled(FALSE);
getChildView("maskcutoff")->setEnabled(FALSE);
getChildView("label maskcutoff")->setEnabled(FALSE);
texture_ctrl->setBakeTextureEnabled(false);
}
else
{
// Tentative: multiple selected with different textures
texture_ctrl->setTentative(TRUE);
texture_ctrl->setEnabled(editable && !has_pbr_material);
texture_ctrl->setImageAssetID(id);
getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f && !has_pbr_material);
getChildView("label alphamode")->setEnabled(editable && mIsAlpha && !has_pbr_material);
getChildView("maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
texture_ctrl->setBakeTextureEnabled(TRUE);
}
}
if (shinytexture_ctrl)
{
shinytexture_ctrl->setTentative( !identical_spec );
shinytexture_ctrl->setEnabled( editable && !has_pbr_material);
shinytexture_ctrl->setImageAssetID( specmap_id );
}
if (bumpytexture_ctrl)
{
bumpytexture_ctrl->setTentative( !identical_norm );
bumpytexture_ctrl->setEnabled( editable && !has_pbr_material);
bumpytexture_ctrl->setImageAssetID( normmap_id );
}
}
// planar align
bool align_planar = false;
bool identical_planar_aligned = false;
{
LLCheckBoxCtrl* cb_planar_align = getChild<LLCheckBoxCtrl>("checkbox planar align");
align_planar = (cb_planar_align && cb_planar_align->get());
bool enabled = (editable && isIdenticalPlanarTexgen() && !texture_info_selected);
childSetValue("checkbox planar align", align_planar && enabled);
childSetVisible("checkbox planar align", enabled);
childSetEnabled("checkbox planar align", enabled);
childSetEnabled("button align textures", enabled && LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1);
if (align_planar && enabled)
{
LLFace* last_face = NULL;
bool identical_face = false;
LLSelectedTE::getFace(last_face, identical_face);
LLPanelFaceGetIsAlignedTEFunctor 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;
getChild<LLUICtrl>("TexScaleU")->setValue(diff_scale_s);
getChild<LLUICtrl>("shinyScaleU")->setValue(spec_scale_s);
getChild<LLUICtrl>("bumpyScaleU")->setValue(norm_scale_s);
getChildView("TexScaleU")->setEnabled(editable && has_material);
getChildView("shinyScaleU")->setEnabled(editable && has_material && specmap_id.notNull());
getChildView("bumpyScaleU")->setEnabled(editable && has_material && normmap_id.notNull());
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);
getChild<LLUICtrl>("TexScaleU")->setTentative( LLSD(diff_scale_tentative));
getChild<LLUICtrl>("shinyScaleU")->setTentative(LLSD(spec_scale_tentative));
getChild<LLUICtrl>("bumpyScaleU")->setTentative(LLSD(norm_scale_tentative));
}
{
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;
getChildView("TexScaleV")->setEnabled(editable && has_material);
getChildView("shinyScaleV")->setEnabled(editable && has_material && specmap_id.notNull());
getChildView("bumpyScaleV")->setEnabled(editable && has_material && normmap_id.notNull());
if (force_set_values)
{
getChild<LLSpinCtrl>("TexScaleV")->forceSetValue(diff_scale_t);
}
else
{
getChild<LLSpinCtrl>("TexScaleV")->setValue(diff_scale_t);
}
getChild<LLUICtrl>("shinyScaleV")->setValue(norm_scale_t);
getChild<LLUICtrl>("bumpyScaleV")->setValue(spec_scale_t);
getChild<LLUICtrl>("TexScaleV")->setTentative(LLSD(diff_scale_tentative));
getChild<LLUICtrl>("shinyScaleV")->setTentative(LLSD(norm_scale_tentative));
getChild<LLUICtrl>("bumpyScaleV")->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);
getChild<LLUICtrl>("TexOffsetU")->setValue( editable ? diff_offset_s : 0.0f);
getChild<LLUICtrl>("bumpyOffsetU")->setValue(editable ? norm_offset_s : 0.0f);
getChild<LLUICtrl>("shinyOffsetU")->setValue(editable ? spec_offset_s : 0.0f);
getChild<LLUICtrl>("TexOffsetU")->setTentative(LLSD(diff_offset_u_tentative));
getChild<LLUICtrl>("shinyOffsetU")->setTentative(LLSD(norm_offset_u_tentative));
getChild<LLUICtrl>("bumpyOffsetU")->setTentative(LLSD(spec_offset_u_tentative));
getChildView("TexOffsetU")->setEnabled(editable && has_material);
getChildView("shinyOffsetU")->setEnabled(editable && has_material && specmap_id.notNull());
getChildView("bumpyOffsetU")->setEnabled(editable && has_material && normmap_id.notNull());
}
{
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);
getChild<LLUICtrl>("TexOffsetV")->setValue( editable ? diff_offset_t : 0.0f);
getChild<LLUICtrl>("bumpyOffsetV")->setValue(editable ? norm_offset_t : 0.0f);
getChild<LLUICtrl>("shinyOffsetV")->setValue(editable ? spec_offset_t : 0.0f);
getChild<LLUICtrl>("TexOffsetV")->setTentative(LLSD(diff_offset_v_tentative));
getChild<LLUICtrl>("shinyOffsetV")->setTentative(LLSD(norm_offset_v_tentative));
getChild<LLUICtrl>("bumpyOffsetV")->setTentative(LLSD(spec_offset_v_tentative));
getChildView("TexOffsetV")->setEnabled(editable && has_material);
getChildView("shinyOffsetV")->setEnabled(editable && has_material && specmap_id.notNull());
getChildView("bumpyOffsetV")->setEnabled(editable && has_material && normmap_id.notNull());
}
// 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;
getChildView("TexRot")->setEnabled(editable && has_material);
getChildView("shinyRot")->setEnabled(editable && has_material && specmap_id.notNull());
getChildView("bumpyRot")->setEnabled(editable && has_material && normmap_id.notNull());
getChild<LLUICtrl>("TexRot")->setTentative(diff_rot_tentative);
getChild<LLUICtrl>("shinyRot")->setTentative(LLSD(norm_rot_tentative));
getChild<LLUICtrl>("bumpyRot")->setTentative(LLSD(spec_rot_tentative));
getChild<LLUICtrl>("TexRot")->setValue( editable ? diff_rot_deg : 0.0f);
getChild<LLUICtrl>("shinyRot")->setValue(editable ? spec_rot_deg : 0.0f);
getChild<LLUICtrl>("bumpyRot")->setValue(editable ? norm_rot_deg : 0.0f);
}
{
F32 glow = 0.f;
bool identical_glow = false;
LLSelectedTE::getGlow(glow,identical_glow);
getChild<LLUICtrl>("glow")->setValue(glow);
getChild<LLUICtrl>("glow")->setTentative(!identical_glow);
getChildView("glow")->setEnabled(editable);
getChildView("glow label")->setEnabled(editable);
}
{
LLCtrlSelectionInterface* combobox_texgen = childGetSelectionInterface("combobox texgen");
if (combobox_texgen)
{
// Maps from enum to combobox entry index
combobox_texgen->selectNthItem(((S32)selected_texgen) >> 1);
}
else
{
LL_WARNS() << "failed childGetSelectionInterface for 'combobox texgen'" << LL_ENDL;
}
getChildView("combobox texgen")->setEnabled(editable);
getChild<LLUICtrl>("combobox texgen")->setTentative(!identical);
getChildView("tex gen")->setEnabled(editable);
}
{
U8 fullbright_flag = 0;
bool identical_fullbright = false;
LLSelectedTE::getFullbright(fullbright_flag,identical_fullbright);
getChild<LLUICtrl>("checkbox fullbright")->setValue((S32)(fullbright_flag != 0));
getChildView("checkbox fullbright")->setEnabled(editable && !has_pbr_material);
getChild<LLUICtrl>("checkbox fullbright")->setTentative(!identical_fullbright);
getChild<LLComboBox>("combobox matmedia")->setEnabledByValue("Materials", !has_pbr_material);
}
// 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);
LLComboBox* mComboTexGen = getChild<LLComboBox>("combobox texgen");
if (mComboTexGen)
{
S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0;
bool enabled = editable && (index != 1);
bool identical_repeats = true;
S32 material_selection = mComboMatMedia->getCurrentIndex();
F32 repeats = 1.0f;
U32 material_type = MATTYPE_DIFFUSE;
if (material_selection == MATMEDIA_MATERIAL)
{
material_type = radio_mat_type->getSelectedIndex();
}
else if (material_selection == MATMEDIA_PBR)
{
enabled = editable && has_pbr_material;
material_type = radio_pbr_type->getSelectedIndex();
}
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()));
}
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()));
}
identical_repeats = identical_norm_repeats;
repeats = repeats_norm;
}
break;
}
BOOL repeats_tentative = !identical_repeats;
LLSpinCtrl* rpt_ctrl = getChild<LLSpinCtrl>("rptctrl");
if (force_set_values)
{
//onCommit, previosly edited element updates related ones
rpt_ctrl->forceSetValue(editable ? repeats : 1.0f);
}
else
{
rpt_ctrl->setValue(editable ? repeats : 1.0f);
}
rpt_ctrl->setTentative(LLSD(repeats_tentative));
rpt_ctrl->setEnabled(has_material && !identical_planar_texgen && enabled);
}
}
// Materials
{
LLMaterialPtr material;
LLSelectedTEMaterial::getCurrent(material, identical);
if (material && editable)
{
LL_DEBUGS("Materials") << material->asLLSD() << LL_ENDL;
// Alpha
LLCtrlSelectionInterface* combobox_alphamode =
childGetSelectionInterface("combobox alphamode");
if (combobox_alphamode)
{
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 ebe none
alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
}
combobox_alphamode->selectNthItem(alpha_mode);
}
else
{
LL_WARNS() << "failed childGetSelectionInterface for 'combobox alphamode'" << LL_ENDL;
}
getChild<LLUICtrl>("maskcutoff")->setValue(material->getAlphaMaskCutoff());
updateAlphaControls();
identical_planar_texgen = isIdenticalPlanarTexgen();
// Shiny (specular)
F32 offset_x, offset_y, repeat_x, repeat_y, rot;
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
texture_ctrl->setImageAssetID(material->getSpecularID());
if (!material->getSpecularID().isNull() && (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();
getChild<LLUICtrl>("shinyScaleU")->setValue(repeat_x);
getChild<LLUICtrl>("shinyScaleV")->setValue(repeat_y);
getChild<LLUICtrl>("shinyRot")->setValue(rot*RAD_TO_DEG);
getChild<LLUICtrl>("shinyOffsetU")->setValue(offset_x);
getChild<LLUICtrl>("shinyOffsetV")->setValue(offset_y);
getChild<LLUICtrl>("glossiness")->setValue(material->getSpecularLightExponent());
getChild<LLUICtrl>("environment")->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().isNull())
{
LLColorSwatchCtrl* shiny_swatch = getChild<LLColorSwatchCtrl>("shinycolorswatch");
LLColor4 new_color = material->getSpecularLightColor();
LLColor4 old_color = shiny_swatch->get();
shiny_swatch->setOriginal(new_color);
shiny_swatch->set(new_color, force_set_values || old_color != new_color || !editable);
}
// Bumpy (normal)
texture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
texture_ctrl->setImageAssetID(material->getNormalID());
if (!material->getNormalID().isNull())
{
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();
getChild<LLUICtrl>("bumpyScaleU")->setValue(repeat_x);
getChild<LLUICtrl>("bumpyScaleV")->setValue(repeat_y);
getChild<LLUICtrl>("bumpyRot")->setValue(rot*RAD_TO_DEG);
getChild<LLUICtrl>("bumpyOffsetU")->setValue(offset_x);
getChild<LLUICtrl>("bumpyOffsetV")->setValue(offset_y);
updateBumpyControls(!material->getNormalID().isNull(), true);
}
}
}
S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
BOOL single_volume = (selected_count == 1);
mMenuClipboardColor->setEnabled(editable && single_volume);
// Set variable values for numeric expressions
LLCalc* calcp = LLCalc::getInstance();
calcp->setVar(LLCalc::TEX_U_SCALE, childGetValue("TexScaleU").asReal());
calcp->setVar(LLCalc::TEX_V_SCALE, childGetValue("TexScaleV").asReal());
calcp->setVar(LLCalc::TEX_U_OFFSET, childGetValue("TexOffsetU").asReal());
calcp->setVar(LLCalc::TEX_V_OFFSET, childGetValue("TexOffsetV").asReal());
calcp->setVar(LLCalc::TEX_ROTATION, childGetValue("TexRot").asReal());
calcp->setVar(LLCalc::TEX_TRANSPARENCY, childGetValue("ColorTrans").asReal());
calcp->setVar(LLCalc::TEX_GLOW, childGetValue("glow").asReal());
}
else
{
// Disable all UICtrls
clearCtrls();
// Disable non-UICtrls
LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
if (pbr_ctrl)
{
pbr_ctrl->setImageAssetID(LLUUID::null);
pbr_ctrl->setEnabled(FALSE);
}
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control");
if (texture_ctrl)
{
texture_ctrl->setImageAssetID( LLUUID::null );
texture_ctrl->setEnabled( FALSE ); // this is a LLUICtrl, but we don't want it to have keyboard focus so we add it as a child, not a ctrl.
// texture_ctrl->setValid(FALSE);
}
LLColorSwatchCtrl* mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
if (mColorSwatch)
{
mColorSwatch->setEnabled( FALSE );
mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") );
mColorSwatch->setValid(FALSE);
}
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
if (radio_mat_type)
{
radio_mat_type->setSelectedIndex(0);
}
getChildView("color trans")->setEnabled(FALSE);
getChildView("rptctrl")->setEnabled(FALSE);
getChildView("tex gen")->setEnabled(FALSE);
getChildView("label shininess")->setEnabled(FALSE);
getChildView("label bumpiness")->setEnabled(FALSE);
getChildView("button align")->setEnabled(FALSE);
getChildView("pbr_from_inventory")->setEnabled(FALSE);
getChildView("edit_selected_pbr")->setEnabled(FALSE);
getChildView("save_selected_pbr")->setEnabled(FALSE);
updateVisibility();
// Set variable values for numeric expressions
LLCalc* calcp = LLCalc::getInstance();
calcp->clearVar(LLCalc::TEX_U_SCALE);
calcp->clearVar(LLCalc::TEX_V_SCALE);
calcp->clearVar(LLCalc::TEX_U_OFFSET);
calcp->clearVar(LLCalc::TEX_V_OFFSET);
calcp->clearVar(LLCalc::TEX_ROTATION);
calcp->clearVar(LLCalc::TEX_TRANSPARENCY);
calcp->clearVar(LLCalc::TEX_GLOW);
}
}
void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool force_set_values)
{
has_pbr_material = false;
const bool editable = objectp->permModify() && !objectp->isPermanentEnforced();
bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable();
// pbr material
LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
if (pbr_ctrl)
{
LLUUID pbr_id;
bool identical_pbr;
LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr);
has_pbr_material = pbr_id.notNull();
pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE);
pbr_ctrl->setEnabled(editable && has_pbr_capabilities);
pbr_ctrl->setImageAssetID(pbr_id);
}
getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities);
getChildView("edit_selected_pbr")->setEnabled(editable && has_pbr_material && has_pbr_capabilities);
getChildView("save_selected_pbr")->setEnabled(objectp->permCopy() && has_pbr_material && has_pbr_capabilities);
const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();
if (show_pbr)
{
const bool new_state = has_pbr_capabilities && has_pbr_material;
LLUICtrl* gltfCtrlTextureScaleU = getChild<LLUICtrl>("gltfTextureScaleU");
LLUICtrl* gltfCtrlTextureScaleV = getChild<LLUICtrl>("gltfTextureScaleV");
LLUICtrl* gltfCtrlTextureRotation = getChild<LLUICtrl>("gltfTextureRotation");
LLUICtrl* gltfCtrlTextureOffsetU = getChild<LLUICtrl>("gltfTextureOffsetU");
LLUICtrl* gltfCtrlTextureOffsetV = getChild<LLUICtrl>("gltfTextureOffsetV");
gltfCtrlTextureScaleU->setEnabled(new_state);
gltfCtrlTextureScaleV->setEnabled(new_state);
gltfCtrlTextureRotation->setEnabled(new_state);
gltfCtrlTextureOffsetU->setEnabled(new_state);
gltfCtrlTextureOffsetV->setEnabled(new_state);
// Control values will be set once per frame in
// setMaterialOverridesFromSelection
sMaterialOverrideSelection.setDirty();
}
}
void LLPanelFace::updateVisibilityGLTF()
{
const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();
LLRadioGroup* radio_pbr_type = findChild<LLRadioGroup>("radio_pbr_type");
radio_pbr_type->setVisible(show_pbr);
const U32 pbr_type = radio_pbr_type->getSelectedIndex();
const bool show_pbr_render_material_id = show_pbr && (pbr_type == PBRTYPE_RENDER_MATERIAL_ID);
getChildView("pbr_control")->setVisible(show_pbr_render_material_id);
getChildView("pbr_from_inventory")->setVisible(show_pbr_render_material_id);
getChildView("edit_selected_pbr")->setVisible(show_pbr_render_material_id);
getChildView("save_selected_pbr")->setVisible(show_pbr_render_material_id);
getChildView("gltfTextureScaleU")->setVisible(show_pbr);
getChildView("gltfTextureScaleV")->setVisible(show_pbr);
getChildView("gltfTextureRotation")->setVisible(show_pbr);
getChildView("gltfTextureOffsetU")->setVisible(show_pbr);
getChildView("gltfTextureOffsetV")->setVisible(show_pbr);
}
void LLPanelFace::updateCopyTexButton()
{
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
mMenuClipboardTexture->setEnabled(objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify()
&& !objectp->isPermanentEnforced() && !objectp->isInventoryPending()
&& (LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1));
std::string tooltip = (objectp && objectp->isInventoryPending()) ? LLTrans::getString("LoadingContents") : getString("paste_options");
mMenuClipboardTexture->setToolTip(tooltip);
}
void LLPanelFace::refresh()
{
LL_DEBUGS("Materials") << LL_ENDL;
getState();
}
void LLPanelFace::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()
))
{
getChildView("add_media")->setEnabled(FALSE);
mTitleMediaText->clear();
clearMediaSettings();
return;
}
std::string url = first_object->getRegion()->getCapability("ObjectMedia");
bool has_media_capability = (!url.empty());
if (!has_media_capability)
{
getChildView("add_media")->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<LLVOVolume*>(node->getObject());
if (NULL != object)
{
if (!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>
{
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 dont 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)
if (object->getTE(face))
if (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.
getChildView("add_media")->setEnabled(editable);
// IF all the faces have media (or all dont 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' re Different Medias' been set on on the faces.
{
media_title = multi_media_info_str;
}
getChildView("delete_media")->setEnabled(bool_has_media && editable);
// TODO: display a list of all media on the face - use 'identical' flag
}
else // not all face has media but at least one does.
{
// seleted faces have not identical value
LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
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();
}
}
getChildView("delete_media")->setEnabled(TRUE);
}
U32 materials_media = mComboMatMedia->getCurrentIndex();
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 LLPanelFace::unloadMedia()
{
// destroy media source used to grab media title
if (mTitleMedia)
mTitleMedia->unloadMediaSource();
}
// static
void LLPanelFace::onMaterialOverrideReceived(const LLUUID& object_id, S32 side)
{
sMaterialOverrideSelection.onSelectedObjectUpdated(object_id, side);
}
//////////////////////////////////////////////////////////////////////////////
//
void LLPanelFace::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 if (mTitleMedia)
{
LLPluginClassMedia* media_plugin = mTitleMedia->getMediaPlugin();
// check if url changed or if we need a new media source
if (mTitleMedia->getCurrentNavUrl() != url || media_plugin == NULL)
{
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 LLPanelFace::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 LLPanelFace::clearMediaSettings()
{
LLFloaterMediaSettings::clearValues(false);
}
void LLPanelFace::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< U8 >
{
functor_getter_controls(const LLMediaEntry &entry) : mMediaEntry(entry) {}
U8 get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_first_click(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< std::string >
{
functor_getter_home_url(const LLMediaEntry& entry) : mMediaEntry(entry) {}
std::string get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< std::string >
{
functor_getter_current_url(const LLMediaEntry& entry) : mMediaEntry(entry) {}
std::string get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_auto_zoom(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_auto_play(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_auto_scale(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_auto_loop(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< int >
{
functor_getter_width_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {}
int get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< int >
{
functor_getter_height_pixels(const LLMediaEntry& entry) : mMediaEntry(entry) {}
int get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_enable_alt_image(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_perms_owner_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_perms_owner_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_perms_group_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_perms_group_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_perms_anyone_interact(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_perms_anyone_control(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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< bool >
{
functor_getter_whitelist_enable(const LLMediaEntry& entry) : mMediaEntry(entry) {}
bool get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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<std::string> value_vector_str = default_media_data.getWhiteList();
struct functor_getter_whitelist_urls : public LLSelectedTEGetFunctor< std::vector<std::string> >
{
functor_getter_whitelist_urls(const LLMediaEntry& entry) : mMediaEntry(entry) {}
std::vector<std::string> get(LLViewerObject* object, S32 face)
{
if (object)
if (object->getTE(face))
if (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 LLPanelFace::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
if (mTitleMediaText)
{
mTitleMediaText->setText(media_title);
// stop looking for a title when we get one
mNeedMediaTitle = false;
};
};
};
}
//
// Static functions
//
// static
F32 LLPanelFace::valueGlow(LLViewerObject* object, S32 face)
{
return (F32)(object->getTE(face)->getGlow());
}
void LLPanelFace::onCommitColor(const LLSD& data)
{
sendColor();
}
void LLPanelFace::onCommitShinyColor(const LLSD& data)
{
LLSelectedTEMaterial::setSpecularLightColor(this, getChild<LLColorSwatchCtrl>("shinycolorswatch")->get());
}
void LLPanelFace::onCommitAlpha(const LLSD& data)
{
sendAlpha();
}
void LLPanelFace::onCancelColor(const LLSD& data)
{
LLSelectMgr::getInstance()->selectionRevertColors();
}
void LLPanelFace::onCancelShinyColor(const LLSD& data)
{
LLSelectMgr::getInstance()->selectionRevertShinyColors();
}
void LLPanelFace::onSelectColor(const LLSD& data)
{
LLSelectMgr::getInstance()->saveSelectedObjectColors();
sendColor();
}
void LLPanelFace::onSelectShinyColor(const LLSD& data)
{
LLSelectedTEMaterial::setSpecularLightColor(this, getChild<LLColorSwatchCtrl>("shinycolorswatch")->get());
LLSelectMgr::getInstance()->saveSelectedShinyColors();
}
// static
void LLPanelFace::onCommitMaterialsMedia(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
// Force to default states to side-step problems with menu contents
// and generally reflecting old state when switching tabs or objects
//
self->updateShinyControls(false,true);
self->updateBumpyControls(false,true);
self->updateUI();
self->refreshMedia();
}
void LLPanelFace::updateVisibility()
{
LLRadioGroup* radio_mat_type = findChild<LLRadioGroup>("radio_material_type");
LLRadioGroup* radio_pbr_type = findChild<LLRadioGroup>("radio_pbr_type");
LLComboBox* combo_shininess = findChild<LLComboBox>("combobox shininess");
LLComboBox* combo_bumpiness = findChild<LLComboBox>("combobox bumpiness");
if (!radio_mat_type || !radio_pbr_type || !mComboMatMedia || !combo_shininess || !combo_bumpiness)
{
LL_WARNS("Materials") << "Combo box not found...exiting." << LL_ENDL;
return;
}
U32 materials_media = mComboMatMedia->getCurrentIndex();
U32 material_type = radio_mat_type->getSelectedIndex();
bool show_media = (materials_media == MATMEDIA_MEDIA) && mComboMatMedia->getEnabled();
bool show_material = materials_media == MATMEDIA_MATERIAL;
bool show_texture = (show_media || (show_material && (material_type == MATTYPE_DIFFUSE) && mComboMatMedia->getEnabled()));
bool show_bumpiness = show_material && (material_type == MATTYPE_NORMAL) && mComboMatMedia->getEnabled();
bool show_shininess = show_material && (material_type == MATTYPE_SPECULAR) && mComboMatMedia->getEnabled();
const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled();
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
const LLGLTFMaterial::TextureInfo texture_info = texture_info_from_pbrtype(pbr_type);
const bool show_pbr_asset = show_pbr && texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT;
radio_mat_type->setVisible(show_material);
// Shared material controls
getChildView("checkbox_sync_settings")->setVisible(show_material || show_media);
getChildView("tex gen")->setVisible(show_material || show_media || show_pbr_asset);
getChildView("combobox texgen")->setVisible(show_material || show_media || show_pbr_asset);
getChildView("button align textures")->setVisible(show_material || show_media);
// Media controls
mTitleMediaText->setVisible(show_media);
getChildView("add_media")->setVisible(show_media);
getChildView("delete_media")->setVisible(show_media);
getChildView("button align")->setVisible(show_media);
// Diffuse texture controls
getChildView("texture control")->setVisible(show_texture && show_material);
getChildView("label alphamode")->setVisible(show_texture && show_material);
getChildView("combobox alphamode")->setVisible(show_texture && show_material);
getChildView("label maskcutoff")->setVisible(false);
getChildView("maskcutoff")->setVisible(false);
if (show_texture && show_material)
{
updateAlphaControls();
}
// texture scale and position controls
getChildView("TexScaleU")->setVisible(show_texture);
getChildView("TexScaleV")->setVisible(show_texture);
getChildView("TexRot")->setVisible(show_texture);
getChildView("TexOffsetU")->setVisible(show_texture);
getChildView("TexOffsetV")->setVisible(show_texture);
// Specular map controls
getChildView("shinytexture control")->setVisible(show_shininess);
getChildView("combobox shininess")->setVisible(show_shininess);
getChildView("label shininess")->setVisible(show_shininess);
getChildView("label glossiness")->setVisible(false);
getChildView("glossiness")->setVisible(false);
getChildView("label environment")->setVisible(false);
getChildView("environment")->setVisible(false);
getChildView("label shinycolor")->setVisible(false);
getChildView("shinycolorswatch")->setVisible(false);
if (show_shininess)
{
updateShinyControls();
}
getChildView("shinyScaleU")->setVisible(show_shininess);
getChildView("shinyScaleV")->setVisible(show_shininess);
getChildView("shinyRot")->setVisible(show_shininess);
getChildView("shinyOffsetU")->setVisible(show_shininess);
getChildView("shinyOffsetV")->setVisible(show_shininess);
// Normal map controls
if (show_bumpiness)
{
updateBumpyControls();
}
getChildView("bumpytexture control")->setVisible(show_bumpiness);
getChildView("combobox bumpiness")->setVisible(show_bumpiness);
getChildView("label bumpiness")->setVisible(show_bumpiness);
getChildView("bumpyScaleU")->setVisible(show_bumpiness);
getChildView("bumpyScaleV")->setVisible(show_bumpiness);
getChildView("bumpyRot")->setVisible(show_bumpiness);
getChildView("bumpyOffsetU")->setVisible(show_bumpiness);
getChildView("bumpyOffsetV")->setVisible(show_bumpiness);
getChild<LLSpinCtrl>("rptctrl")->setVisible(show_material || show_media);
// PBR controls
updateVisibilityGLTF();
}
// static
void LLPanelFace::onCommitMaterialType(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
// Force to default states to side-step problems with menu contents
// and generally reflecting old state when switching tabs or objects
//
self->updateShinyControls(false,true);
self->updateBumpyControls(false,true);
self->updateUI();
}
// static
void LLPanelFace::onCommitPbrType(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*)userdata;
// Force to default states to side-step problems with menu contents
// and generally reflecting old state when switching tabs or objects
//
self->updateUI();
}
// static
void LLPanelFace::onCommitBump(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
LLComboBox* mComboBumpiness = self->getChild<LLComboBox>("combobox bumpiness");
if(!mComboBumpiness)
return;
U32 bumpiness = mComboBumpiness->getCurrentIndex();
self->sendBump(bumpiness);
}
// static
void LLPanelFace::onCommitTexGen(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->sendTexGen();
}
// static
void LLPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_shiny_combobox)
{
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
LLUUID shiny_texture_ID = texture_ctrl->getImageAssetID();
LL_DEBUGS("Materials") << "Shiny texture selected: " << shiny_texture_ID << LL_ENDL;
LLComboBox* comboShiny = getChild<LLComboBox>("combobox shininess");
if(mess_with_shiny_combobox)
{
if (!comboShiny)
{
return;
}
if (!shiny_texture_ID.isNull() && is_setting_texture)
{
if (!comboShiny->itemExists(USE_TEXTURE))
{
comboShiny->add(USE_TEXTURE);
}
comboShiny->setSimple(USE_TEXTURE);
}
else
{
if (comboShiny->itemExists(USE_TEXTURE))
{
comboShiny->remove(SHINY_TEXTURE);
comboShiny->selectFirstItem();
}
}
}
else
{
if (shiny_texture_ID.isNull() && comboShiny && comboShiny->itemExists(USE_TEXTURE))
{
comboShiny->remove(SHINY_TEXTURE);
comboShiny->selectFirstItem();
}
}
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
U32 materials_media = mComboMatMedia->getCurrentIndex();
U32 material_type = radio_mat_type->getSelectedIndex();
bool show_material = (materials_media == MATMEDIA_MATERIAL);
bool show_shininess = show_material && (material_type == MATTYPE_SPECULAR) && mComboMatMedia->getEnabled();
U32 shiny_value = comboShiny->getCurrentIndex();
bool show_shinyctrls = (shiny_value == SHINY_TEXTURE) && show_shininess; // Use texture
getChildView("label glossiness")->setVisible(show_shinyctrls);
getChildView("glossiness")->setVisible(show_shinyctrls);
getChildView("label environment")->setVisible(show_shinyctrls);
getChildView("environment")->setVisible(show_shinyctrls);
getChildView("label shinycolor")->setVisible(show_shinyctrls);
getChildView("shinycolorswatch")->setVisible(show_shinyctrls);
}
// static
void LLPanelFace::updateBumpyControls(bool is_setting_texture, bool mess_with_combobox)
{
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
LLUUID bumpy_texture_ID = texture_ctrl->getImageAssetID();
LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL;
LLComboBox* comboBumpy = getChild<LLComboBox>("combobox bumpiness");
if (!comboBumpy)
{
return;
}
if (mess_with_combobox)
{
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
LLUUID bumpy_texture_ID = texture_ctrl->getImageAssetID();
LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL;
if (!bumpy_texture_ID.isNull() && is_setting_texture)
{
if (!comboBumpy->itemExists(USE_TEXTURE))
{
comboBumpy->add(USE_TEXTURE);
}
comboBumpy->setSimple(USE_TEXTURE);
}
else
{
if (comboBumpy->itemExists(USE_TEXTURE))
{
comboBumpy->remove(BUMPY_TEXTURE);
comboBumpy->selectFirstItem();
}
}
}
}
// static
void LLPanelFace::onCommitShiny(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
LLComboBox* mComboShininess = self->getChild<LLComboBox>("combobox shininess");
if(!mComboShininess)
return;
U32 shininess = mComboShininess->getCurrentIndex();
self->sendShiny(shininess);
}
// static
void LLPanelFace::updateAlphaControls()
{
LLComboBox* comboAlphaMode = getChild<LLComboBox>("combobox alphamode");
if (!comboAlphaMode)
{
return;
}
U32 alpha_value = comboAlphaMode->getCurrentIndex();
bool show_alphactrls = (alpha_value == ALPHAMODE_MASK); // Alpha masking
U32 mat_media = MATMEDIA_MATERIAL;
if (mComboMatMedia)
{
mat_media = mComboMatMedia->getCurrentIndex();
}
U32 mat_type = MATTYPE_DIFFUSE;
LLRadioGroup* radio_mat_type = getChild<LLRadioGroup>("radio_material_type");
if(radio_mat_type)
{
mat_type = radio_mat_type->getSelectedIndex();
}
show_alphactrls = show_alphactrls && (mat_media == MATMEDIA_MATERIAL);
show_alphactrls = show_alphactrls && (mat_type == MATTYPE_DIFFUSE);
getChildView("label maskcutoff")->setVisible(show_alphactrls);
getChildView("maskcutoff")->setVisible(show_alphactrls);
}
// static
void LLPanelFace::onCommitAlphaMode(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->updateAlphaControls();
LLSelectedTEMaterial::setDiffuseAlphaMode(self,self->getCurrentDiffuseAlphaMode());
}
// static
void LLPanelFace::onCommitFullbright(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->sendFullbright();
}
// static
void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->sendGlow();
}
// static
BOOL LLPanelFace::onDragPbr(LLUICtrl*, 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 LLPanelFace::onCommitPbr(const LLSD& data)
{
LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
if (!pbr_ctrl) return;
if (!pbr_ctrl->getTentative())
{
// we grab the item id first, because we want to do a
// permissions check in the selection manager. ARGH!
LLUUID id = pbr_ctrl->getImageItemID();
if (id.isNull())
{
id = pbr_ctrl->getImageAssetID();
}
if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
{
// If failed to set material, refresh pbr_ctrl's value
refresh();
}
}
}
void LLPanelFace::onCancelPbr(const LLSD& data)
{
LLSelectMgr::getInstance()->selectionRevertGLTFMaterials();
}
void LLPanelFace::onSelectPbr(const LLSD& data)
{
LLSelectMgr::getInstance()->saveSelectedObjectTextures();
LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
if (!pbr_ctrl) return;
if (!pbr_ctrl->getTentative())
{
// we grab the item id first, because we want to do a
// permissions check in the selection manager. ARGH!
LLUUID id = pbr_ctrl->getImageItemID();
if (id.isNull())
{
id = pbr_ctrl->getImageAssetID();
}
if (LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
{
LLSelectedTEMaterial::setMaterialID(this, id);
}
else
{
refresh();
}
}
}
// static
BOOL LLPanelFace::onDragTexture(LLUICtrl*, 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 LLPanelFace::onCommitTexture( const LLSD& data )
{
add(LLStatViewer::EDIT_TEXTURE, 1);
sendTexture();
}
void LLPanelFace::onCancelTexture(const LLSD& data)
{
LLSelectMgr::getInstance()->selectionRevertTextures();
}
void LLPanelFace::onSelectTexture(const LLSD& data)
{
LLSelectMgr::getInstance()->saveSelectedObjectTextures();
sendTexture();
LLGLenum image_format;
bool identical_image_format = false;
LLSelectedTE::getImageFormat(image_format, identical_image_format);
LLCtrlSelectionInterface* combobox_alphamode =
childGetSelectionInterface("combobox alphamode");
U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
if (combobox_alphamode)
{
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 LLPanelFace...resorting to no alpha" << LL_ENDL;
}
break;
}
combobox_alphamode->selectNthItem(alpha_mode);
}
LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode());
}
void LLPanelFace::onCloseTexturePicker(const LLSD& data)
{
LL_DEBUGS("Materials") << data << LL_ENDL;
updateUI();
}
void LLPanelFace::onCommitSpecularTexture( const LLSD& data )
{
LL_DEBUGS("Materials") << data << LL_ENDL;
sendShiny(SHINY_TEXTURE);
}
void LLPanelFace::onCommitNormalTexture( const LLSD& data )
{
LL_DEBUGS("Materials") << data << LL_ENDL;
LLUUID nmap_id = getCurrentNormalMap();
sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE);
}
void LLPanelFace::onCancelSpecularTexture(const LLSD& data)
{
U8 shiny = 0;
bool identical_shiny = false;
LLSelectedTE::getShiny(shiny, identical_shiny);
LLUUID spec_map_id = getChild<LLTextureCtrl>("shinytexture control")->getImageAssetID();
shiny = spec_map_id.isNull() ? shiny : SHINY_TEXTURE;
sendShiny(shiny);
}
void LLPanelFace::onCancelNormalTexture(const LLSD& data)
{
U8 bumpy = 0;
bool identical_bumpy = false;
LLSelectedTE::getBumpmap(bumpy, identical_bumpy);
LLUUID spec_map_id = getChild<LLTextureCtrl>("bumpytexture control")->getImageAssetID();
bumpy = spec_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
sendBump(bumpy);
}
void LLPanelFace::onSelectSpecularTexture(const LLSD& data)
{
LL_DEBUGS("Materials") << data << LL_ENDL;
sendShiny(SHINY_TEXTURE);
}
void LLPanelFace::onSelectNormalTexture(const LLSD& data)
{
LL_DEBUGS("Materials") << data << LL_ENDL;
LLUUID nmap_id = getCurrentNormalMap();
sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE);
}
//////////////////////////////////////////////////////////////////////////////
// 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
void LLPanelFace::onClickBtnEditMedia(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*)userdata;
self->refreshMedia();
LLFloaterReg::showInstance("media_settings");
}
//////////////////////////////////////////////////////////////////////////////
// called when a user wants to delete media from a prim or prim face
void LLPanelFace::onClickBtnDeleteMedia(LLUICtrl* ctrl, void* userdata)
{
LLNotificationsUtil::add("DeleteMedia", LLSD(), LLSD(), deleteMediaConfirm);
}
//////////////////////////////////////////////////////////////////////////////
// called when a user wants to add media to a prim or prim face
void LLPanelFace::onClickBtnAddMedia(LLUICtrl* ctrl, void* userdata)
{
// check if multiple faces are selected
if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())
{
LLPanelFace* self = (LLPanelFace*)userdata;
self->refreshMedia();
LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), multipleFacesSelectedConfirm);
}
else
{
onClickBtnEditMedia(ctrl, userdata);
}
}
// static
bool LLPanelFace::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;
}
// static
bool LLPanelFace::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 LLPanelFace::syncOffsetX(LLPanelFace* self, F32 offsetU)
{
LLSelectedTEMaterial::setNormalOffsetX(self,offsetU);
LLSelectedTEMaterial::setSpecularOffsetX(self,offsetU);
self->getChild<LLSpinCtrl>("TexOffsetU")->forceSetValue(offsetU);
self->sendTextureInfo();
}
//static
void LLPanelFace::syncOffsetY(LLPanelFace* self, F32 offsetV)
{
LLSelectedTEMaterial::setNormalOffsetY(self,offsetV);
LLSelectedTEMaterial::setSpecularOffsetY(self,offsetV);
self->getChild<LLSpinCtrl>("TexOffsetV")->forceSetValue(offsetV);
self->sendTextureInfo();
}
//static
void LLPanelFace::onCommitMaterialBumpyOffsetX(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetX(self,self->getCurrentBumpyOffsetU());
}
else
{
LLSelectedTEMaterial::setNormalOffsetX(self,self->getCurrentBumpyOffsetU());
}
}
//static
void LLPanelFace::onCommitMaterialBumpyOffsetY(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetY(self,self->getCurrentBumpyOffsetV());
}
else
{
LLSelectedTEMaterial::setNormalOffsetY(self,self->getCurrentBumpyOffsetV());
}
}
//static
void LLPanelFace::onCommitMaterialShinyOffsetX(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetX(self, self->getCurrentShinyOffsetU());
}
else
{
LLSelectedTEMaterial::setSpecularOffsetX(self,self->getCurrentShinyOffsetU());
}
}
//static
void LLPanelFace::onCommitMaterialShinyOffsetY(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetY(self,self->getCurrentShinyOffsetV());
}
else
{
LLSelectedTEMaterial::setSpecularOffsetY(self,self->getCurrentShinyOffsetV());
}
}
//static
void LLPanelFace::syncRepeatX(LLPanelFace* self, F32 scaleU)
{
LLSelectedTEMaterial::setNormalRepeatX(self,scaleU);
LLSelectedTEMaterial::setSpecularRepeatX(self,scaleU);
self->sendTextureInfo();
}
//static
void LLPanelFace::syncRepeatY(LLPanelFace* self, F32 scaleV)
{
LLSelectedTEMaterial::setNormalRepeatY(self,scaleV);
LLSelectedTEMaterial::setSpecularRepeatY(self,scaleV);
self->sendTextureInfo();
}
//static
void LLPanelFace::onCommitMaterialBumpyScaleX(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
F32 bumpy_scale_u = self->getCurrentBumpyScaleU();
if (self->isIdenticalPlanarTexgen())
{
bumpy_scale_u *= 0.5f;
}
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
self->getChild<LLSpinCtrl>("TexScaleU")->forceSetValue(self->getCurrentBumpyScaleU());
syncRepeatX(self, bumpy_scale_u);
}
else
{
LLSelectedTEMaterial::setNormalRepeatX(self,bumpy_scale_u);
}
}
//static
void LLPanelFace::onCommitMaterialBumpyScaleY(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
F32 bumpy_scale_v = self->getCurrentBumpyScaleV();
if (self->isIdenticalPlanarTexgen())
{
bumpy_scale_v *= 0.5f;
}
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
self->getChild<LLSpinCtrl>("TexScaleV")->forceSetValue(self->getCurrentBumpyScaleV());
syncRepeatY(self, bumpy_scale_v);
}
else
{
LLSelectedTEMaterial::setNormalRepeatY(self,bumpy_scale_v);
}
}
//static
void LLPanelFace::onCommitMaterialShinyScaleX(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
F32 shiny_scale_u = self->getCurrentShinyScaleU();
if (self->isIdenticalPlanarTexgen())
{
shiny_scale_u *= 0.5f;
}
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
self->getChild<LLSpinCtrl>("TexScaleU")->forceSetValue(self->getCurrentShinyScaleU());
syncRepeatX(self, shiny_scale_u);
}
else
{
LLSelectedTEMaterial::setSpecularRepeatX(self,shiny_scale_u);
}
}
//static
void LLPanelFace::onCommitMaterialShinyScaleY(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
F32 shiny_scale_v = self->getCurrentShinyScaleV();
if (self->isIdenticalPlanarTexgen())
{
shiny_scale_v *= 0.5f;
}
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
self->getChild<LLSpinCtrl>("TexScaleV")->forceSetValue(self->getCurrentShinyScaleV());
syncRepeatY(self, shiny_scale_v);
}
else
{
LLSelectedTEMaterial::setSpecularRepeatY(self,shiny_scale_v);
}
}
//static
void LLPanelFace::syncMaterialRot(LLPanelFace* self, F32 rot, int te)
{
LLSelectedTEMaterial::setNormalRotation(self,rot * DEG_TO_RAD, te);
LLSelectedTEMaterial::setSpecularRotation(self,rot * DEG_TO_RAD, te);
self->sendTextureInfo();
}
//static
void LLPanelFace::onCommitMaterialBumpyRot(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
self->getChild<LLSpinCtrl>("TexRot")->forceSetValue(self->getCurrentBumpyRot());
syncMaterialRot(self, self->getCurrentBumpyRot());
}
else
{
if ((bool)self->childGetValue("checkbox planar align").asBoolean())
{
LLFace* last_face = NULL;
bool identical_face = false;
LLSelectedTE::getFace(last_face, identical_face);
LLPanelFaceSetAlignedTEFunctor setfunc(self, last_face);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
else
{
LLSelectedTEMaterial::setNormalRotation(self, self->getCurrentBumpyRot() * DEG_TO_RAD);
}
}
}
//static
void LLPanelFace::onCommitMaterialShinyRot(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
self->getChild<LLSpinCtrl>("TexRot")->forceSetValue(self->getCurrentShinyRot());
syncMaterialRot(self, self->getCurrentShinyRot());
}
else
{
if ((bool)self->childGetValue("checkbox planar align").asBoolean())
{
LLFace* last_face = NULL;
bool identical_face = false;
LLSelectedTE::getFace(last_face, identical_face);
LLPanelFaceSetAlignedTEFunctor setfunc(self, last_face);
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
}
else
{
LLSelectedTEMaterial::setSpecularRotation(self, self->getCurrentShinyRot() * DEG_TO_RAD);
}
}
}
//static
void LLPanelFace::onCommitMaterialGloss(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
LLSelectedTEMaterial::setSpecularLightExponent(self,self->getCurrentGlossiness());
}
//static
void LLPanelFace::onCommitMaterialEnv(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
llassert_always(self);
LLSelectedTEMaterial::setEnvironmentIntensity(self,self->getCurrentEnvIntensity());
}
//static
void LLPanelFace::onCommitMaterialMaskCutoff(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
LLSelectedTEMaterial::setAlphaMaskCutoff(self,self->getCurrentAlphaMaskCutoff());
}
// static
void LLPanelFace::onCommitTextureInfo( LLUICtrl* ctrl, void* userdata )
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->sendTextureInfo();
// vertical scale and repeats per meter depends on each other, so force set on changes
self->updateUI(true);
}
// static
void LLPanelFace::onCommitTextureScaleX( LLUICtrl* ctrl, void* userdata )
{
LLPanelFace* self = (LLPanelFace*) userdata;
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
F32 bumpy_scale_u = self->getChild<LLUICtrl>("TexScaleU")->getValue().asReal();
if (self->isIdenticalPlanarTexgen())
{
bumpy_scale_u *= 0.5f;
}
syncRepeatX(self, bumpy_scale_u);
}
else
{
self->sendTextureInfo();
}
self->updateUI(true);
}
// static
void LLPanelFace::onCommitTextureScaleY( LLUICtrl* ctrl, void* userdata )
{
LLPanelFace* self = (LLPanelFace*) userdata;
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
F32 bumpy_scale_v = self->getChild<LLUICtrl>("TexScaleV")->getValue().asReal();
if (self->isIdenticalPlanarTexgen())
{
bumpy_scale_v *= 0.5f;
}
syncRepeatY(self, bumpy_scale_v);
}
else
{
self->sendTextureInfo();
}
self->updateUI(true);
}
// static
void LLPanelFace::onCommitTextureRot( LLUICtrl* ctrl, void* userdata )
{
LLPanelFace* self = (LLPanelFace*) userdata;
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncMaterialRot(self, self->getChild<LLUICtrl>("TexRot")->getValue().asReal());
}
else
{
self->sendTextureInfo();
}
self->updateUI(true);
}
// static
void LLPanelFace::onCommitTextureOffsetX( LLUICtrl* ctrl, void* userdata )
{
LLPanelFace* self = (LLPanelFace*) userdata;
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetX(self, self->getChild<LLUICtrl>("TexOffsetU")->getValue().asReal());
}
else
{
self->sendTextureInfo();
}
self->updateUI(true);
}
// static
void LLPanelFace::onCommitTextureOffsetY( LLUICtrl* ctrl, void* userdata )
{
LLPanelFace* self = (LLPanelFace*) userdata;
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
syncOffsetY(self, self->getChild<LLUICtrl>("TexOffsetV")->getValue().asReal());
}
else
{
self->sendTextureInfo();
}
self->updateUI(true);
}
// Commit the number of repeats per meter
// static
void LLPanelFace::onCommitRepeatsPerMeter(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
LLUICtrl* repeats_ctrl = self->getChild<LLUICtrl>("rptctrl");
U32 materials_media = self->mComboMatMedia->getCurrentIndex();
U32 material_type = 0;
if (materials_media == MATMEDIA_PBR)
{
LLRadioGroup* radio_mat_type = self->getChild<LLRadioGroup>("radio_pbr_type");
material_type = radio_mat_type->getSelectedIndex();
}
if (materials_media == MATMEDIA_MATERIAL)
{
LLRadioGroup* radio_mat_type = self->getChild<LLRadioGroup>("radio_material_type");
material_type = radio_mat_type->getSelectedIndex();
}
F32 repeats_per_meter = repeats_ctrl->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);
LLUICtrl* bumpy_scale_u = self->getChild<LLUICtrl>("bumpyScaleU");
LLUICtrl* bumpy_scale_v = self->getChild<LLUICtrl>("bumpyScaleV");
LLUICtrl* shiny_scale_u = self->getChild<LLUICtrl>("shinyScaleU");
LLUICtrl* shiny_scale_v = self->getChild<LLUICtrl>("shinyScaleV");
if (gSavedSettings.getBOOL("SyncMaterialSettings"))
{
LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter );
bumpy_scale_u->setValue(obj_scale_s * repeats_per_meter);
bumpy_scale_v->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatX(self,obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatY(self,obj_scale_t * repeats_per_meter);
shiny_scale_u->setValue(obj_scale_s * repeats_per_meter);
shiny_scale_v->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatX(self,obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatY(self,obj_scale_t * repeats_per_meter);
}
else
{
switch (material_type)
{
case MATTYPE_DIFFUSE:
{
LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter );
}
break;
case MATTYPE_NORMAL:
{
bumpy_scale_u->setValue(obj_scale_s * repeats_per_meter);
bumpy_scale_v->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatX(self,obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setNormalRepeatY(self,obj_scale_t * repeats_per_meter);
}
break;
case MATTYPE_SPECULAR:
{
shiny_scale_u->setValue(obj_scale_s * repeats_per_meter);
shiny_scale_v->setValue(obj_scale_t * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatX(self,obj_scale_s * repeats_per_meter);
LLSelectedTEMaterial::setSpecularRepeatY(self,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
self->updateUI(true);
}
struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor
{
virtual bool apply(LLViewerObject* object, S32 te)
{
viewer_media_t pMediaImpl;
const LLTextureEntry* tep = object->getTE(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 LLPanelFace::onClickAutoFix(void* userdata)
{
LLPanelFaceSetMediaFunctor setfunc;
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
LLPanelFaceSendFunctor sendfunc;
LLSelectMgr::getInstance()->getSelection()->applyToObjects(&sendfunc);
}
void LLPanelFace::onAlignTexture(void* userdata)
{
LLPanelFace* self = (LLPanelFace*)userdata;
self->alignTestureLayer();
}
void LLPanelFace::onClickBtnLoadInvPBR(void* userdata)
{
// Shouldn't this be "save to inventory?"
LLPanelFace* self = (LLPanelFace*)userdata;
LLTextureCtrl* pbr_ctrl = self->findChild<LLTextureCtrl>("pbr_control");
pbr_ctrl->showPicker(true);
}
void LLPanelFace::onClickBtnEditPBR(void* userdata)
{
LLMaterialEditor::loadLive();
}
void LLPanelFace::onClickBtnSavePBR(void* userdata)
{
LLMaterialEditor::saveObjectsMaterialAs();
}
enum EPasteMode
{
PASTE_COLOR,
PASTE_TEXTURE
};
struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor
{
LLPanelFacePasteTexFunctor(LLPanelFace* 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:
LLPanelFace *mPanelFace;
EPasteMode mMode;
};
struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor
{
LLPanelFaceUpdateFunctor(bool update_media)
: mUpdateMedia(update_media)
{}
virtual bool apply(LLViewerObject* object)
{
object->sendTEUpdate();
if (mUpdateMedia)
{
LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
if (vo && vo->hasMedia())
{
vo->sendMediaDataUpdate();
}
}
return true;
}
private:
bool mUpdateMedia;
};
struct LLPanelFaceNavigateHomeFunctor : 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 LLPanelFace::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<LLUUID, LLUUID> 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 LLPanelFace::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();
LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR);
selected_objects->applyToTEs(&paste_func);
LLPanelFaceUpdateFunctor sendfunc(false);
selected_objects->applyToObjects(&sendfunc);
}
void LLPanelFace::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 LLPanelFace::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)
{
return;
}
if (mClipboardParams.has("texture"))
{
mClipboardParams["texture"].clear();
}
else
{
mClipboardParams["texture"] = LLSD::emptyArray();
}
std::map<LLUUID, LLUUID> 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["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"]["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<LLUUID, LLUUID>::iterator iter = asset_item_map.find(id);
if (iter != asset_item_map.end())
{
item_id = iter->second;
}
else
{
// What this does is simply searches inventory for item with same asset id,
// as result it is Hightly unreliable, leaves little control to user, borderline hack
// but there are little options to preserve permissions - multiple inventory
// items might reference same asset and inventory search is expensive.
bool no_transfer = false;
if (objectp->getInventoryItemByAsset(id))
{
no_transfer = !objectp->getInventoryItemByAsset(id)->getIsFullPerm();
}
item_id = get_copy_free_item_by_asset_id(id, no_transfer);
// record value to avoid repeating inventory search when possible
asset_item_map[id] = item_id;
}
}
if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID()))
{
full_perm = true;
from_library = true;
}
{
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 LLPanelFace::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)
{
// 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();
LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE);
selected_objects->applyToTEs(&paste_func);
LLPanelFaceUpdateFunctor sendfunc(true);
selected_objects->applyToObjects(&sendfunc);
LLGLTFMaterialList::flushUpdates();
LLPanelFaceNavigateHomeFunctor navigate_home_func;
selected_objects->applyToTEs(&navigate_home_func);
}
void LLPanelFace::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 happend, but if it does happen, we
// might need to add a notification to user that paste will fail
// since inventory isn't fully loaded
LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL;
}
}
}
// for case when item got removed from inventory after we pressed 'copy'
// or texture got pasted into previous object
if (!itemp_res && !full_perm)
{
// Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable.
LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL;
// Todo: fix this, we are often searching same texture multiple times (equal to number of faces)
// Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work
LLViewerInventoryCategory::cat_array_t cats;
LLViewerInventoryItem::item_array_t items;
LLAssetIDMatches asset_id_matches(imageid);
gInventory.collectDescendentsIf(LLUUID::null,
cats,
items,
LLInventoryModel::INCLUDE_TRASH,
asset_id_matches);
// Extremely unreliable and perfomance unfriendly.
// But we need this to check permissions and it is how texture control finds items
for (S32 i = 0; i < items.size(); i++)
{
LLViewerInventoryItem* itemp = items[i];
if (itemp && itemp->isFinished())
{
// dropTextureAllFaces will fail if incomplete
LLPermissions item_permissions = itemp->getPermissions();
if (item_permissions.allowOperationBy(PERM_COPY,
gAgent.getID(),
gAgent.getGroupID()))
{
itemp_res = itemp;
break; // first match
}
}
}
}
if (itemp_res)
{
if (te == -1) // all faces
{
LLToolDragAndDrop::dropTextureAllFaces(objectp,
itemp_res,
from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
LLUUID::null);
}
else // one face
{
LLToolDragAndDrop::dropTextureOneFace(objectp,
te,
itemp_res,
from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT,
LLUUID::null,
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());
}
// 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<LLVOVolume*>(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();
LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id);
// 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);
LLColor4 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"]["SpecRot"].asInteger(), te, object_id);
if (te_data.has("te") && te_data["te"].has("shiny"))
{
objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger());
}
}
}
}
void LLPanelFace::menuDoToSelected(const LLSD& userdata)
{
std::string command = userdata.asString();
// paste
if (command == "color_paste")
{
onPasteColor();
}
else if (command == "texture_paste")
{
onPasteTexture();
}
// copy
else if (command == "color_copy")
{
onCopyColor();
}
else if (command == "texture_copy")
{
onCopyTexture();
}
}
bool LLPanelFace::menuEnableItem(const LLSD& userdata)
{
std::string command = userdata.asString();
// paste options
if (command == "color_paste")
{
return mClipboardParams.has("color");
}
else if (command == "texture_paste")
{
return mClipboardParams.has("texture");
}
return false;
}
// static
void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
{
LLPanelFace* self = (LLPanelFace*) userdata;
self->getState();
self->sendTextureInfo();
}
void LLPanelFace::updateGLTFTextureTransform(float value, U32 pbr_type, std::function<void(LLGLTFMaterial::TextureTransform*)> edit)
{
U32 texture_info_start;
U32 texture_info_end;
const LLGLTFMaterial::TextureInfo texture_info = texture_info_from_pbrtype(pbr_type);
if (texture_info == LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT)
{
texture_info_start = 0;
texture_info_end = LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT;
}
else
{
texture_info_start = texture_info_from_pbrtype(pbr_type);
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);
}
});
LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
if (node)
{
LLViewerObject* object = node->getObject();
sMaterialOverrideSelection.setObjectUpdatePending(object->getID(), node->getLastSelectedTE());
}
}
void LLPanelFace::setMaterialOverridesFromSelection()
{
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
const LLGLTFMaterial::TextureInfo texture_info = texture_info_from_pbrtype(pbr_type);
U32 texture_info_start;
U32 texture_info_end;
if (texture_info == LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT)
{
texture_info_start = 0;
texture_info_end = LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT;
}
else
{
texture_info_start = texture_info;
texture_info_end = texture_info + 1;
}
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;
for (U32 i = texture_info_start; i < texture_info_end; ++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<float>([&](const LLGLTFMaterial* mat)
{
return mat ? mat->mTextureTransform[i].mScale[VX] : 0.f;
}, this_transform.mScale[VX], this_scale_u_same, true, 1e-3f);
readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat)
{
return mat ? mat->mTextureTransform[i].mScale[VY] : 0.f;
}, this_transform.mScale[VY], this_scale_v_same, true, 1e-3f);
readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat)
{
return mat ? mat->mTextureTransform[i].mRotation : 0.f;
}, this_transform.mRotation, this_rotation_same, true, 1e-3f);
readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat)
{
return mat ? mat->mTextureTransform[i].mOffset[VX] : 0.f;
}, this_transform.mOffset[VX], this_offset_u_same, true, 1e-3f);
readSelectedGLTFMaterial<float>([&](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 = getChild<LLUICtrl>("gltfTextureScaleU");
LLUICtrl* gltfCtrlTextureScaleV = getChild<LLUICtrl>("gltfTextureScaleV");
LLUICtrl* gltfCtrlTextureRotation = getChild<LLUICtrl>("gltfTextureRotation");
LLUICtrl* gltfCtrlTextureOffsetU = getChild<LLUICtrl>("gltfTextureOffsetU");
LLUICtrl* gltfCtrlTextureOffsetV = getChild<LLUICtrl>("gltfTextureOffsetV");
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 LLPanelFace::Selection::connect()
{
if (!mSelectConnection.connected())
{
mSelectConnection = LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&LLPanelFace::Selection::onSelectionChanged, this));
}
}
bool LLPanelFace::Selection::update()
{
const bool changed = mChanged || compareSelection();
mChanged = false;
return changed;
}
void LLPanelFace::Selection::setObjectUpdatePending(const LLUUID &object_id, S32 side)
{
mPendingObjectID = object_id;
mPendingSide = side;
}
void LLPanelFace::Selection::onSelectedObjectUpdated(const LLUUID& object_id, S32 side)
{
if (object_id == mSelectedObjectID && side == mSelectedSide)
{
mChanged = true;
}
}
bool LLPanelFace::Selection::compareSelection()
{
if (!mNeedsSelectionCheck)
{
return false;
}
mNeedsSelectionCheck = false;
const S32 old_object_count = mSelectedObjectCount;
const LLUUID old_object_id = mSelectedObjectID;
const S32 old_side = mSelectedSide;
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
LLSelectNode* node = selection->getFirstNode();
if (node)
{
LLViewerObject* object = node->getObject();
mSelectedObjectCount = selection->getObjectCount();
mSelectedObjectID = object->getID();
mSelectedSide = node->getLastSelectedTE();
}
else
{
mSelectedObjectCount = 0;
mSelectedObjectID = LLUUID::null;
mSelectedSide = -1;
}
const bool selection_changed = old_object_count != mSelectedObjectCount || old_object_id != mSelectedObjectID || old_side != mSelectedSide;
mChanged = mChanged || selection_changed;
return selection_changed;
}
void LLPanelFace::onCommitGLTFTextureScaleU(LLUICtrl* ctrl)
{
const float value = ctrl->getValue().asReal();
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
updateGLTFTextureTransform(value, pbr_type, [&](LLGLTFMaterial::TextureTransform* new_transform)
{
new_transform->mScale.mV[VX] = value;
});
}
void LLPanelFace::onCommitGLTFTextureScaleV(LLUICtrl* ctrl)
{
const float value = ctrl->getValue().asReal();
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
updateGLTFTextureTransform(value, pbr_type, [&](LLGLTFMaterial::TextureTransform* new_transform)
{
new_transform->mScale.mV[VY] = value;
});
}
void LLPanelFace::onCommitGLTFRotation(LLUICtrl* ctrl)
{
const float value = ctrl->getValue().asReal() * DEG_TO_RAD;
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
updateGLTFTextureTransform(value, pbr_type, [&](LLGLTFMaterial::TextureTransform* new_transform)
{
new_transform->mRotation = value;
});
}
void LLPanelFace::onCommitGLTFTextureOffsetU(LLUICtrl* ctrl)
{
const float value = ctrl->getValue().asReal();
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
updateGLTFTextureTransform(value, pbr_type, [&](LLGLTFMaterial::TextureTransform* new_transform)
{
new_transform->mOffset.mV[VX] = value;
});
}
void LLPanelFace::onCommitGLTFTextureOffsetV(LLUICtrl* ctrl)
{
const float value = ctrl->getValue().asReal();
const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex();
updateGLTFTextureTransform(value, pbr_type, [&](LLGLTFMaterial::TextureTransform* new_transform)
{
new_transform->mOffset.mV[VY] = value;
});
}
void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp)
{
LL_DEBUGS("Materials") << "item asset " << itemp->getAssetUUID() << LL_ENDL;
LLRadioGroup* radio_mat_type = findChild<LLRadioGroup>("radio_material_type");
if(!radio_mat_type)
{
return;
}
U32 mattype = radio_mat_type->getSelectedIndex();
std::string which_control="texture control";
switch (mattype)
{
case MATTYPE_SPECULAR:
which_control = "shinytexture control";
break;
case MATTYPE_NORMAL:
which_control = "bumpytexture control";
break;
// no default needed
}
LL_DEBUGS("Materials") << "control " << which_control << LL_ENDL;
LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>(which_control);
if (texture_ctrl)
{
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");
}
}
}
void LLPanelFace::onPbrSelectionChanged(LLInventoryItem* itemp)
{
LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control");
if (pbr_ctrl)
{
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)
{
pbr_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
pbr_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale);
if (gSavedSettings.getBOOL("TextureLivePreview"))
{
LLNotificationsUtil::add("LivePreviewUnavailable");
}
}
}
bool LLPanelFace::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 LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical_face)
{
struct LLSelectedTEGetFace : public LLSelectedTEGetFunctor<LLFace *>
{
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 LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)
{
LLGLenum image_format;
struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor<LLGLenum>
{
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 LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
{
struct LLSelectedTEGetTexId : public LLSelectedTEGetFunctor<LLUUID>
{
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 LLPanelFace::LLSelectedTE::getPbrMaterialId(LLUUID& id, bool& identical)
{
struct LLSelectedTEGetmatId : public LLSelectedTEGetFunctor<LLUUID>
{
LLUUID get(LLViewerObject* object, S32 te_index)
{
return object->getRenderMaterialID(te_index);
}
} func;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, id);
}
void LLPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material)
{
struct MaterialFunctor : public LLSelectedTEGetFunctor<LLMaterialPtr>
{
LLMaterialPtr get(LLViewerObject* object, S32 te_index)
{
return object->getTE(te_index)->getMaterialParams();
}
} func;
identical_material = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_ptr);
}
void LLPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool& identical)
{
struct LLSelectedTEGetMaxSpecRepeats : public LLSelectedTEGetFunctor<F32>
{
F32 get(LLViewerObject* object, S32 face)
{
LLMaterial* mat = object->getTE(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 LLPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool& identical)
{
struct LLSelectedTEGetMaxNormRepeats : public LLSelectedTEGetFunctor<F32>
{
F32 get(LLViewerObject* object, S32 face)
{
LLMaterial* mat = object->getTE(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 LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha)
{
struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor<U8>
{
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 LLPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical)
{
struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>
{
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 LLPanelFace::LLSelectedTE::getObjectScaleT(F32& scale_t, bool& identical)
{
struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>
{
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 LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identical)
{
struct LLSelectedTEGetMaxDiffuseRepeats : public LLSelectedTEGetFunctor<F32>
{
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->getTE(face)->mScaleS / object->getScale().mV[s_axis];
F32 repeats_t = object->getTE(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 );
}