Files
SingularityViewer/indra/newview/llpanelobject.cpp
Liru Færs 9522e385cd Merge viewer-benefits
Replace MAX_AGENT_ATTACHMENTS with sim based response
Replace max groups with benefits based response
Upload costs are now handled by sim response
Removed no-longer-needed lleconomy files and classes
Removed dead fields from hippolimits and hippogridmanager
Also removed lame LL code that is redundant and silly

On non SL grids, when values are not provided for benefits, they will be
set to the values granting maximum liberty.
Old standardized responses still work when benefits aren't implemented.
2020-03-23 20:15:59 -04:00

2670 lines
76 KiB
C++

/**
* @file llpanelobject.cpp
* @brief Object editing (position, scale, etc.) in the tools floater
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
// file include
#include "llpanelobject.h"
// linden library includes
#include "llerror.h"
#include "llfontgl.h"
#include "llpermissionsflags.h"
#include "llstring.h"
#include "llvolume.h"
#include "m3math.h"
// project includes
#include "llagent.h"
#include "llbutton.h"
#include "llcalc.h"
#include "llcheckboxctrl.h"
#include "llcolorswatch.h"
#include "llcombobox.h"
#include "llfocusmgr.h"
#include "llinventoryfunctions.h"
#include "llmanipscale.h"
#include "llnotificationsutil.h"
#include "llpanelobjectinventory.h"
#include "llpreviewscript.h"
#include "llresmgr.h"
#include "llselectmgr.h"
#include "llspinctrl.h"
#include "lltexturectrl.h"
#include "lltextbox.h"
#include "lltool.h"
#include "lltoolcomp.h"
#include "lltoolmgr.h"
#include "llui.h"
#include "llviewerobject.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llwindow.h"
#include "llvovolume.h"
#include "llworld.h"
#include "pipeline.h"
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
#include "llfirstuse.h"
#include "lldrawpool.h"
#include "hippolimits.h"
// [RLVa:KB]
#include "rlvhandler.h"
#include "llvoavatarself.h"
// [/RLVa:KB]
//
// Constants
//
enum {
MI_BOX,
MI_CYLINDER,
MI_PRISM,
MI_SPHERE,
MI_TORUS,
MI_TUBE,
MI_RING,
MI_SCULPT,
// <edit>
MI_HEMICYLINDER,
MI_SPIRAL_CIRCLE,
MI_SPIRAL_SQUARE,
MI_SPIRAL_TRIANGLE,
MI_SPIRAL_SEMICIRCLE,
MI_TEST_CYLINDER,
MI_TEST_BOX,
MI_TEST_PRISM,
MI_TEST_HEMICYLINDER,
// </edit>
MI_NONE,
MI_VOLUME_COUNT
};
enum {
MI_HOLE_SAME,
MI_HOLE_CIRCLE,
MI_HOLE_SQUARE,
MI_HOLE_TRIANGLE,
MI_HOLE_COUNT
};
// *TODO:translate (deprecated, so very low priority)
static const std::string LEGACY_FULLBRIGHT_DESC("Fullbright (Legacy)");
LLVector3 LLPanelObject::mClipboardPos;
LLVector3 LLPanelObject::mClipboardSize;
LLVector3 LLPanelObject::mClipboardRot;
LLVolumeParams LLPanelObject::mClipboardVolumeParams;
const LLFlexibleObjectData* LLPanelObject::mClipboardFlexiParams = NULL;
const LLLightParams* LLPanelObject::mClipboardLightParams = NULL;
const LLSculptParams* LLPanelObject::mClipboardSculptParams = NULL;
const LLLightImageParams* LLPanelObject::mClipboardLightImageParams = NULL;
BOOL LLPanelObject::hasParamClipboard = FALSE;
BOOL LLPanelObject::postBuild()
{
setMouseOpaque(FALSE);
//--------------------------------------------------------
// Top
//--------------------------------------------------------
// Build constant tipsheet
//childSetAction("build_math_constants",onClickBuildConstants,this);
// Lock checkbox
mCheckLock = getChild<LLCheckBoxCtrl>("checkbox locked");
childSetCommitCallback("checkbox locked",onCommitLock,this);
// Physical checkbox
mCheckPhysics = getChild<LLCheckBoxCtrl>("Physical Checkbox Ctrl");
childSetCommitCallback("Physical Checkbox Ctrl",onCommitPhysics,this);
// Temporary checkbox
mCheckTemporary = getChild<LLCheckBoxCtrl>("Temporary Checkbox Ctrl");
childSetCommitCallback("Temporary Checkbox Ctrl",onCommitTemporary,this);
// Phantom checkbox
mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
// Position
mLabelPosition = getChild<LLTextBox>("label position");
mCtrlPosX = getChild<LLSpinCtrl>("Pos X");
childSetCommitCallback("Pos X",onCommitPosition,this);
mCtrlPosY = getChild<LLSpinCtrl>("Pos Y");
childSetCommitCallback("Pos Y",onCommitPosition,this);
mCtrlPosZ = getChild<LLSpinCtrl>("Pos Z");
childSetCommitCallback("Pos Z",onCommitPosition,this);
// Scale
mLabelSize = getChild<LLTextBox>("label size");
mCtrlScaleX = getChild<LLSpinCtrl>("Scale X");
childSetCommitCallback("Scale X",onCommitScale,this);
// Scale Y
mCtrlScaleY = getChild<LLSpinCtrl>("Scale Y");
childSetCommitCallback("Scale Y",onCommitScale,this);
// Scale Z
mCtrlScaleZ = getChild<LLSpinCtrl>("Scale Z");
childSetCommitCallback("Scale Z",onCommitScale,this);
// Rotation
mLabelRotation = getChild<LLTextBox>("label rotation");
mCtrlRotX = getChild<LLSpinCtrl>("Rot X");
childSetCommitCallback("Rot X",onCommitRotation,this);
mCtrlRotY = getChild<LLSpinCtrl>("Rot Y");
childSetCommitCallback("Rot Y",onCommitRotation,this);
mCtrlRotZ = getChild<LLSpinCtrl>("Rot Z");
childSetCommitCallback("Rot Z",onCommitRotation,this);
mBtnLinkObj = getChild<LLButton>("link_obj");
childSetAction("link_obj",onLinkObj, this);
mBtnUnlinkObj = getChild<LLButton>("unlink_obj");
childSetAction("unlink_obj",onUnlinkObj, this);
mBtnCopyPos = getChild<LLButton>("copypos");
childSetAction("copypos",onCopyPos, this);
mBtnPastePos = getChild<LLButton>("pastepos");
childSetAction("pastepos",onPastePos, this);
mBtnPastePosClip = getChild<LLButton>("pasteposclip");
childSetAction("pasteposclip",onPastePosClip, this);
mBtnCopySize = getChild<LLButton>("copysize");
childSetAction("copysize",onCopySize, this);
mBtnPasteSize = getChild<LLButton>("pastesize");
childSetAction("pastesize",onPasteSize, this);
mBtnPasteSizeClip = getChild<LLButton>("pastesizeclip");
childSetAction("pastesizeclip",onPasteSizeClip, this);
mBtnCopyRot = getChild<LLButton>("copyrot");
childSetAction("copyrot",onCopyRot, this);
mBtnPasteRot = getChild<LLButton>("pasterot");
childSetAction("pasterot",onPasteRot, this);
mBtnPasteRotClip = getChild<LLButton>("pasterotclip");
childSetAction("pasterotclip",onPasteRotClip, this);
mBtnCopyParams = getChild<LLButton>("copyparams");
childSetAction("copyparams",onCopyParams, this);
mBtnPasteParams = getChild<LLButton>("pasteparams");
childSetAction("pasteparams",onPasteParams, this);
//--------------------------------------------------------
// material type popup
mLabelMaterial = getChild<LLTextBox>("label material");
mComboMaterial = getChild<LLComboBox>("material");
childSetCommitCallback("material",onCommitMaterial,this);
mComboMaterial->removeall();
// <edit>
/*
// *TODO:translate
for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin();
iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter)
{
LLMaterialInfo* minfop = *iter;
if (minfop->mMCode != LL_MCODE_LIGHT)
{
mComboMaterial->add(minfop->mName);
}
}
*/
for(U8 mcode = 0; mcode < 0x10; mcode++)
{
mComboMaterial->add(LLMaterialTable::basic.getName(mcode));
}
// </edit>
mComboMaterialItemCount = mComboMaterial->getItemCount();
// Base Type
mLabelBaseType = getChild<LLTextBox>("label basetype");
mComboBaseType = getChild<LLComboBox>("comboBaseType");
childSetCommitCallback("comboBaseType",onCommitParametric,this);
// Cut
mLabelCut = getChild<LLTextBox>("text cut");
mSpinCutBegin = getChild<LLSpinCtrl>("cut begin");
childSetCommitCallback("cut begin",onCommitParametric,this);
mSpinCutBegin->setValidateBeforeCommit( precommitValidate );
mSpinCutEnd = getChild<LLSpinCtrl>("cut end");
childSetCommitCallback("cut end",onCommitParametric,this);
mSpinCutEnd->setValidateBeforeCommit( &precommitValidate );
// Hollow / Skew
mLabelHollow = getChild<LLTextBox>("text hollow");
mLabelSkew = getChild<LLTextBox>("text skew");
mSpinHollow = getChild<LLSpinCtrl>("Scale 1");
childSetCommitCallback("Scale 1",onCommitParametric,this);
mSpinHollow->setValidateBeforeCommit( &precommitValidate );
mSpinSkew = getChild<LLSpinCtrl>("Skew");
childSetCommitCallback("Skew",onCommitParametric,this);
mSpinSkew->setValidateBeforeCommit( &precommitValidate );
mLabelHoleType = getChild<LLTextBox>("Hollow Shape");
// Hole Type
mComboHoleType = getChild<LLComboBox>("hole");
childSetCommitCallback("hole",onCommitParametric,this);
// Twist
mLabelTwist = getChild<LLTextBox>("text twist");
mSpinTwistBegin = getChild<LLSpinCtrl>("Twist Begin");
childSetCommitCallback("Twist Begin",onCommitParametric,this);
mSpinTwistBegin->setValidateBeforeCommit( precommitValidate );
mSpinTwist = getChild<LLSpinCtrl>("Twist End");
childSetCommitCallback("Twist End",onCommitParametric,this);
mSpinTwist->setValidateBeforeCommit( &precommitValidate );
// Scale
mSpinScaleX = getChild<LLSpinCtrl>("Taper Scale X");
childSetCommitCallback("Taper Scale X",onCommitParametric,this);
mSpinScaleX->setValidateBeforeCommit( &precommitValidate );
mSpinScaleY = getChild<LLSpinCtrl>("Taper Scale Y");
childSetCommitCallback("Taper Scale Y",onCommitParametric,this);
mSpinScaleY->setValidateBeforeCommit( &precommitValidate );
// Shear
mLabelShear = getChild<LLTextBox>("text topshear");
mSpinShearX = getChild<LLSpinCtrl>("Shear X");
childSetCommitCallback("Shear X",onCommitParametric,this);
mSpinShearX->setValidateBeforeCommit( &precommitValidate );
mSpinShearY = getChild<LLSpinCtrl>("Shear Y");
childSetCommitCallback("Shear Y",onCommitParametric,this);
mSpinShearY->setValidateBeforeCommit( &precommitValidate );
// Path / Profile
mCtrlPathBegin = getChild<LLSpinCtrl>("Path Limit Begin");
childSetCommitCallback("Path Limit Begin",onCommitParametric,this);
mCtrlPathBegin->setValidateBeforeCommit( &precommitValidate );
mCtrlPathEnd = getChild<LLSpinCtrl>("Path Limit End");
childSetCommitCallback("Path Limit End",onCommitParametric,this);
mCtrlPathEnd->setValidateBeforeCommit( &precommitValidate );
// Taper
mLabelTaper = getChild<LLTextBox>("text taper2");
mSpinTaperX = getChild<LLSpinCtrl>("Taper X");
childSetCommitCallback("Taper X",onCommitParametric,this);
mSpinTaperX->setValidateBeforeCommit( precommitValidate );
mSpinTaperY = getChild<LLSpinCtrl>("Taper Y");
childSetCommitCallback("Taper Y",onCommitParametric,this);
mSpinTaperY->setValidateBeforeCommit( precommitValidate );
// Radius Offset / Revolutions
mLabelRadiusOffset = getChild<LLTextBox>("text radius delta");
mLabelRevolutions = getChild<LLTextBox>("text revolutions");
mSpinRadiusOffset = getChild<LLSpinCtrl>("Radius Offset");
childSetCommitCallback("Radius Offset",onCommitParametric,this);
mSpinRadiusOffset->setValidateBeforeCommit( &precommitValidate );
mSpinRevolutions = getChild<LLSpinCtrl>("Revolutions");
childSetCommitCallback("Revolutions",onCommitParametric,this);
mSpinRevolutions->setValidateBeforeCommit( &precommitValidate );
// Sculpt
mCtrlSculptTexture = getChild<LLTextureCtrl>("sculpt texture control");
if (mCtrlSculptTexture)
{
mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE));
mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 ));
mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 ));
mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 ));
mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 ));
// Don't allow (no copy) or (no transfer) textures to be selected during immediate mode
mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
// Allow any texture to be used during non-immediate mode.
mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE);
LLAggregatePermissions texture_perms;
if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms))
{
BOOL can_copy =
texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY ||
texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL;
BOOL can_transfer =
texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY ||
texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL;
mCtrlSculptTexture->setCanApplyImmediately(can_copy && can_transfer);
}
else
{
mCtrlSculptTexture->setCanApplyImmediately(FALSE);
}
}
mLabelSculptType = getChild<LLTextBox>("label sculpt type");
mCtrlSculptType = getChild<LLComboBox>("sculpt type control");
childSetCommitCallback("sculpt type control", onCommitSculptType, this);
mCtrlSculptMirror = getChild<LLCheckBoxCtrl>("sculpt mirror control");
childSetCommitCallback("sculpt mirror control", onCommitSculptType, this);
mCtrlSculptInvert = getChild<LLCheckBoxCtrl>("sculpt invert control");
childSetCommitCallback("sculpt invert control", onCommitSculptType, this);
// Start with everyone disabled
clearCtrls();
return TRUE;
}
LLPanelObject::LLPanelObject(const std::string& name)
: LLPanel(name),
mIsPhysical(FALSE),
mIsTemporary(FALSE),
mIsPhantom(FALSE),
mSelectedType(MI_BOX)
{
}
LLPanelObject::~LLPanelObject()
{
// Children all cleaned up by default view destructor.
}
const LLUUID& LLPanelObject::findItemID(const LLUUID& asset_id)
{
LLViewerInventoryCategory::cat_array_t cats;
LLViewerInventoryItem::item_array_t items;
LLAssetIDMatches asset_id_matches(asset_id);
gInventory.collectDescendentsIf(LLUUID::null,
cats,
items,
LLInventoryModel::INCLUDE_TRASH,
asset_id_matches);
if (items.size())
{
// search for copyable version first
for (U32 i = 0; i < items.size(); i++)
{
LLInventoryItem* itemp = items[i];
LLPermissions item_permissions = itemp->getPermissions();
if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
{
return itemp->getUUID();
}
}
}
return LLUUID::null;
}
void LLPanelObject::getState( )
{
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
LLViewerObject* root_objectp = objectp;
if(!objectp)
{
objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
// *FIX: shouldn't we just keep the child?
if (objectp)
{
LLViewerObject* parentp = objectp->getRootEdit();
if (parentp)
{
root_objectp = parentp;
}
else
{
root_objectp = objectp;
}
}
}
LLCalc* calcp = LLCalc::getInstance();
LLVOVolume *volobjp = NULL;
if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
{
volobjp = (LLVOVolume *)objectp;
}
if( !objectp )
{
//forfeit focus
if (gFocusMgr.childHasKeyboardFocus(this))
{
gFocusMgr.setKeyboardFocus(NULL);
}
// Disable all text input fields
clearCtrls();
calcp->clearAllVariables();
return;
}
// can move or rotate only linked group with move permissions
BOOL enable_move = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced());
BOOL enable_scale = enable_move && objectp->permModify();
BOOL enable_rotate = enable_move;
S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ))
&& (selected_count == 1);
if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1)
{
enable_move = FALSE;
enable_scale = FALSE;
enable_rotate = FALSE;
}
// [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g
if ( (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SITTP))) )
{
if ( (isAgentAvatarValid()) && (gAgentAvatarp->isSitting()) && (gAgentAvatarp->getRoot() == objectp->getRootEdit()) )
enable_move = enable_scale = enable_rotate = FALSE;
}
// [/RLVa:KB]
LLVector3 vec;
if (enable_move)
{
vec = objectp->getPositionEdit();
mCtrlPosX->set( vec.mV[VX] );
mCtrlPosY->set( vec.mV[VY] );
mCtrlPosZ->set( vec.mV[VZ] );
calcp->setVar(LLCalc::X_POS, vec.mV[VX]);
calcp->setVar(LLCalc::Y_POS, vec.mV[VY]);
calcp->setVar(LLCalc::Z_POS, vec.mV[VZ]);
}
else
{
mCtrlPosX->clear();
mCtrlPosY->clear();
mCtrlPosZ->clear();
calcp->clearVar(LLCalc::X_POS);
calcp->clearVar(LLCalc::Y_POS);
calcp->clearVar(LLCalc::Z_POS);
}
mLabelPosition->setEnabled( enable_move );
mCtrlPosX->setEnabled(enable_move);
mCtrlPosY->setEnabled(enable_move);
mCtrlPosZ->setEnabled(enable_move);
mBtnLinkObj->setEnabled(LLSelectMgr::getInstance()->enableLinkObjects());
LLViewerObject* linkset_parent = objectp->getSubParent()? objectp->getSubParent() : objectp;
mBtnUnlinkObj->setEnabled(
LLSelectMgr::getInstance()->enableUnlinkObjects()
&& (linkset_parent->numChildren() >= 1)
&& LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()<=1);
mBtnCopyPos->setEnabled(enable_move);
mBtnPastePos->setEnabled(enable_move);
mBtnPastePosClip->setEnabled(enable_move);
if (enable_scale)
{
vec = objectp->getScale();
mCtrlScaleX->set( vec.mV[VX] );
mCtrlScaleY->set( vec.mV[VY] );
mCtrlScaleZ->set( vec.mV[VZ] );
calcp->setVar(LLCalc::X_SCALE, vec.mV[VX]);
calcp->setVar(LLCalc::Y_SCALE, vec.mV[VY]);
calcp->setVar(LLCalc::Z_SCALE, vec.mV[VZ]);
}
else
{
mCtrlScaleX->clear();
mCtrlScaleY->clear();
mCtrlScaleZ->clear();
calcp->setVar(LLCalc::X_SCALE, 0.f);
calcp->setVar(LLCalc::Y_SCALE, 0.f);
calcp->setVar(LLCalc::Z_SCALE, 0.f);
}
mLabelSize->setEnabled( enable_scale );
mCtrlScaleX->setEnabled( enable_scale );
mCtrlScaleY->setEnabled( enable_scale );
mCtrlScaleZ->setEnabled( enable_scale );
mBtnCopySize->setEnabled( enable_scale );
mBtnPasteSize->setEnabled( enable_scale );
mBtnPasteSizeClip->setEnabled( enable_scale );
mCtrlPosX->setMaxValue(objectp->getRegion()->getWidth());
mCtrlPosY->setMaxValue(objectp->getRegion()->getWidth()); // Singu TODO: VarRegions, getLength()
mCtrlPosZ->setMaxValue(gHippoLimits->getMaxHeight());
mCtrlScaleX->setMaxValue(gHippoLimits->getMaxPrimScale());
mCtrlScaleY->setMaxValue(gHippoLimits->getMaxPrimScale());
mCtrlScaleZ->setMaxValue(gHippoLimits->getMaxPrimScale());
mCtrlScaleX->setMinValue(gHippoLimits->getMinPrimScale());
mCtrlScaleY->setMinValue(gHippoLimits->getMinPrimScale());
mCtrlScaleZ->setMinValue(gHippoLimits->getMinPrimScale());
LLQuaternion object_rot = objectp->getRotationEdit();
object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ]));
mCurEulerDegrees *= RAD_TO_DEG;
mCurEulerDegrees.mV[VX] = fmod(ll_round(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
mCurEulerDegrees.mV[VY] = fmod(ll_round(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
mCurEulerDegrees.mV[VZ] = fmod(ll_round(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
if (enable_rotate)
{
mCtrlRotX->set( mCurEulerDegrees.mV[VX] );
mCtrlRotY->set( mCurEulerDegrees.mV[VY] );
mCtrlRotZ->set( mCurEulerDegrees.mV[VZ] );
calcp->setVar(LLCalc::X_ROT, mCurEulerDegrees.mV[VX]);
calcp->setVar(LLCalc::Y_ROT, mCurEulerDegrees.mV[VY]);
calcp->setVar(LLCalc::Z_ROT, mCurEulerDegrees.mV[VZ]);
}
else
{
mCtrlRotX->clear();
mCtrlRotY->clear();
mCtrlRotZ->clear();
calcp->clearVar(LLCalc::X_ROT);
calcp->clearVar(LLCalc::Y_ROT);
calcp->clearVar(LLCalc::Z_ROT);
}
mLabelRotation->setEnabled( enable_rotate );
mCtrlRotX->setEnabled( enable_rotate );
mCtrlRotY->setEnabled( enable_rotate );
mCtrlRotZ->setEnabled( enable_rotate );
mBtnCopyRot->setEnabled( enable_rotate );
mBtnPasteRot->setEnabled( enable_rotate );
mBtnPasteRotClip->setEnabled( enable_rotate );
mBtnCopyParams->setEnabled( single_volume );
mBtnPasteParams->setEnabled( single_volume );
LLUUID owner_id;
std::string owner_name;
LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
// BUG? Check for all objects being editable?
S32 roots_selected = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount();
BOOL editable = root_objectp->permModify();
// Select Single Message
childSetVisible("select_single", FALSE);
childSetVisible("edit_object", FALSE);
if (!editable || single_volume || selected_count <= 1)
{
childSetVisible("edit_object", TRUE);
childSetEnabled("edit_object", TRUE);
}
else
{
childSetVisible("select_single", TRUE);
childSetEnabled("select_single", TRUE);
}
BOOL is_flexible = volobjp && volobjp->isFlexible();
BOOL is_permanent = root_objectp->flagObjectPermanent();
BOOL is_permanent_enforced = root_objectp->isPermanentEnforced();
BOOL is_character = root_objectp->flagCharacter();
llassert(!is_permanent || !is_character); // should never have a permanent object that is also a character
// Lock checkbox - only modifiable if you own the object.
BOOL self_owned = (gAgent.getID() == owner_id);
mCheckLock->setEnabled( roots_selected > 0 && self_owned && !is_permanent_enforced);
// More lock and debit checkbox - get the values
BOOL valid;
U32 owner_mask_on;
U32 owner_mask_off;
valid = LLSelectMgr::getInstance()->selectGetPerm(PERM_OWNER, &owner_mask_on, &owner_mask_off);
if(valid)
{
if(owner_mask_on & PERM_MOVE)
{
// owner can move, so not locked
mCheckLock->set(FALSE);
mCheckLock->setTentative(FALSE);
}
else if(owner_mask_off & PERM_MOVE)
{
// owner can't move, so locked
mCheckLock->set(TRUE);
mCheckLock->setTentative(FALSE);
}
else
{
// some locked, some not locked
mCheckLock->set(FALSE);
mCheckLock->setTentative(TRUE);
}
}
// Physics checkbox
mIsPhysical = root_objectp->flagUsePhysics();
llassert(!is_permanent || !mIsPhysical); // should never have a permanent object that is also physical
mCheckPhysics->set( mIsPhysical );
mCheckPhysics->setEnabled( roots_selected>0
&& (editable || gAgent.isGodlike())
&& !is_flexible && !is_permanent);
mIsTemporary = root_objectp->flagTemporaryOnRez();
llassert(!is_permanent || !mIsTemporary); // should never has a permanent object that is also temporary
mCheckTemporary->set( mIsTemporary );
mCheckTemporary->setEnabled( roots_selected>0 && editable && !is_permanent);
mIsPhantom = root_objectp->flagPhantom();
BOOL is_volume_detect = root_objectp->flagVolumeDetect();
llassert(!is_character || !mIsPhantom); // should never have a character that is also a phantom
mCheckPhantom->set( mIsPhantom );
mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible && !is_permanent_enforced && !is_character && !is_volume_detect);
// Update material part
// slightly inefficient - materials are unique per object, not per TE
U8 material_code = 0;
struct f : public LLSelectedTEGetFunctor<U8>
{
U8 get(LLViewerObject* object, S32 te)
{
return object->getMaterial();
}
} func;
bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code );
if (editable && single_volume && material_same)
{
mComboMaterial->setEnabled( TRUE );
mLabelMaterial->setEnabled( TRUE );
// <edit>
/*
if (material_code == LL_MCODE_LIGHT)
{
if (mComboMaterial->getItemCount() == mComboMaterialItemCount)
{
mComboMaterial->add(LEGACY_FULLBRIGHT_DESC);
}
mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC);
}
else
{
if (mComboMaterial->getItemCount() != mComboMaterialItemCount)
{
mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC);
}
// *TODO:Translate
mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code)));
}
*/
mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code)));
// </edit>
}
else
{
mComboMaterial->setEnabled( FALSE );
mLabelMaterial->setEnabled( FALSE );
}
//----------------------------------------------------------------------------
S32 selected_item = MI_BOX;
S32 selected_hole = MI_HOLE_SAME;
BOOL enabled = FALSE;
BOOL hole_enabled = FALSE;
F32 scale_x=1.f, scale_y=1.f;
BOOL isMesh = FALSE;
if( !objectp || !objectp->getVolume() || !editable || !single_volume)
{
// Clear out all geometry fields.
mComboBaseType->clear();
mSpinHollow->clear();
mSpinCutBegin->clear();
mSpinCutEnd->clear();
mCtrlPathBegin->clear();
mCtrlPathEnd->clear();
mSpinScaleX->clear();
mSpinScaleY->clear();
mSpinTwist->clear();
mSpinTwistBegin->clear();
mComboHoleType->clear();
mSpinShearX->clear();
mSpinShearY->clear();
mSpinTaperX->clear();
mSpinTaperY->clear();
mSpinRadiusOffset->clear();
mSpinRevolutions->clear();
mSpinSkew->clear();
mSelectedType = MI_NONE;
}
else
{
// Only allowed to change these parameters for objects
// that you have permissions on AND are not attachments.
enabled = root_objectp->permModify() && !root_objectp->isPermanentEnforced();
// Volume type
const LLVolumeParams &volume_params = objectp->getVolume()->getParams();
U8 path = volume_params.getPathParams().getCurveType();
U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
U8 profile = profile_and_hole & LL_PCODE_PROFILE_MASK;
U8 hole = profile_and_hole & LL_PCODE_HOLE_MASK;
// Scale goes first so we can differentiate between a sphere and a torus,
// which have the same profile and path types.
// Scale
scale_x = volume_params.getRatioX();
scale_y = volume_params.getRatioY();
BOOL linear_path = (path == LL_PCODE_PATH_LINE) || (path == LL_PCODE_PATH_FLEXIBLE);
if ( linear_path && profile == LL_PCODE_PROFILE_CIRCLE )
{
selected_item = MI_CYLINDER;
}
else if ( linear_path && profile == LL_PCODE_PROFILE_SQUARE )
{
selected_item = MI_BOX;
}
else if ( linear_path && profile == LL_PCODE_PROFILE_ISOTRI )
{
selected_item = MI_PRISM;
}
else if ( linear_path && profile == LL_PCODE_PROFILE_EQUALTRI )
{
selected_item = MI_PRISM;
}
else if ( linear_path && profile == LL_PCODE_PROFILE_RIGHTTRI )
{
selected_item = MI_PRISM;
}
// <edit> that was messin up my hemicylinder
//else if (path == LL_PCODE_PATH_FLEXIBLE) // shouldn't happen
//{
// selected_item = MI_CYLINDER; // reasonable default
//}
// </edit>
else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y > 0.75f)
{
selected_item = MI_SPHERE;
}
else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE && scale_y <= 0.75f)
{
selected_item = MI_TORUS;
}
else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_CIRCLE_HALF)
{
selected_item = MI_SPHERE;
}
// <edit> spirals are supported by me
//else if ( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE )
//{
// // Spirals aren't supported. Make it into a sphere. JC
// selected_item = MI_SPHERE;
//}
// </edit>
else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_EQUALTRI )
{
selected_item = MI_RING;
}
else if ( path == LL_PCODE_PATH_CIRCLE && profile == LL_PCODE_PROFILE_SQUARE && scale_y <= 0.75f)
{
selected_item = MI_TUBE;
}
// <edit>
else if( linear_path && profile == LL_PCODE_PROFILE_CIRCLE_HALF)
{
selected_item = MI_HEMICYLINDER;
}
// Spirals
else if( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE )
{
selected_item = MI_SPIRAL_CIRCLE;
}
else if( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_SQUARE )
{
selected_item = MI_SPIRAL_SQUARE;
}
else if( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_ISOTRI )
{
selected_item = MI_SPIRAL_TRIANGLE;
}
else if( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_EQUALTRI )
{
selected_item = MI_SPIRAL_TRIANGLE;
}
else if( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_RIGHTTRI )
{
selected_item = MI_SPIRAL_TRIANGLE;
}
else if( path == LL_PCODE_PATH_CIRCLE2 && profile == LL_PCODE_PROFILE_CIRCLE_HALF )
{
selected_item = MI_SPIRAL_SEMICIRCLE;
}
// Test path
else if( path == LL_PCODE_PATH_TEST && profile == LL_PCODE_PROFILE_CIRCLE )
{
selected_item = MI_TEST_CYLINDER;
}
else if( path == LL_PCODE_PATH_TEST && profile == LL_PCODE_PROFILE_SQUARE )
{
selected_item = MI_TEST_BOX;
}
else if( path == LL_PCODE_PATH_TEST && profile == LL_PCODE_PROFILE_ISOTRI )
{
selected_item = MI_TEST_PRISM;
}
else if( path == LL_PCODE_PATH_TEST && profile == LL_PCODE_PROFILE_EQUALTRI )
{
selected_item = MI_TEST_PRISM;
}
else if( path == LL_PCODE_PATH_TEST && profile == LL_PCODE_PROFILE_RIGHTTRI )
{
selected_item = MI_TEST_PRISM;
}
else if( path == LL_PCODE_PATH_TEST && profile == LL_PCODE_PROFILE_CIRCLE_HALF )
{
selected_item = MI_TEST_HEMICYLINDER;
}
// </edit>
else
{
LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL;
selected_item = MI_BOX;
}
if (objectp->getSculptParams())
{
selected_item = MI_SCULPT;
LLFirstUse::useSculptedPrim();
}
mComboBaseType ->setCurrentByIndex( selected_item );
mSelectedType = selected_item;
// Grab S path
F32 begin_s = volume_params.getBeginS();
F32 end_s = volume_params.getEndS();
// Compute cut and advanced cut from S and T
F32 begin_t = volume_params.getBeginT();
F32 end_t = volume_params.getEndT();
// Hollowness
F32 hollow = 100.f * volume_params.getHollow();
mSpinHollow->set( hollow );
calcp->setVar(LLCalc::HOLLOW, hollow);
// All hollow objects allow a shape to be selected.
if (hollow > 0.f)
{
switch (hole)
{
case LL_PCODE_HOLE_CIRCLE:
selected_hole = MI_HOLE_CIRCLE;
break;
case LL_PCODE_HOLE_SQUARE:
selected_hole = MI_HOLE_SQUARE;
break;
case LL_PCODE_HOLE_TRIANGLE:
selected_hole = MI_HOLE_TRIANGLE;
break;
case LL_PCODE_HOLE_SAME:
default:
selected_hole = MI_HOLE_SAME;
break;
}
mComboHoleType->setCurrentByIndex( selected_hole );
hole_enabled = enabled;
}
else
{
mComboHoleType->setCurrentByIndex( MI_HOLE_SAME );
hole_enabled = FALSE;
}
// Cut interpretation varies based on base object type
F32 cut_begin, cut_end, adv_cut_begin, adv_cut_end;
// <edit>
//if ( selected_item == MI_SPHERE || selected_item == MI_TORUS ||
// selected_item == MI_TUBE || selected_item == MI_RING )
if(!linear_path)
// </edit>
{
cut_begin = begin_t;
cut_end = end_t;
adv_cut_begin = begin_s;
adv_cut_end = end_s;
}
else
{
cut_begin = begin_s;
cut_end = end_s;
adv_cut_begin = begin_t;
adv_cut_end = end_t;
}
mSpinCutBegin ->set( cut_begin );
mSpinCutEnd ->set( cut_end );
mCtrlPathBegin ->set( adv_cut_begin );
mCtrlPathEnd ->set( adv_cut_end );
calcp->setVar(LLCalc::CUT_BEGIN, cut_begin);
calcp->setVar(LLCalc::CUT_END, cut_end);
calcp->setVar(LLCalc::PATH_BEGIN, adv_cut_begin);
calcp->setVar(LLCalc::PATH_END, adv_cut_end);
// Twist
F32 twist = volume_params.getTwist();
F32 twist_begin = volume_params.getTwistBegin();
// Check the path type for conversion.
// <edit>
//if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE)
if(linear_path)
// </edit>
{
twist *= OBJECT_TWIST_LINEAR_MAX;
twist_begin *= OBJECT_TWIST_LINEAR_MAX;
}
else
{
twist *= OBJECT_TWIST_MAX;
twist_begin *= OBJECT_TWIST_MAX;
}
mSpinTwist ->set( twist );
mSpinTwistBegin ->set( twist_begin );
calcp->setVar(LLCalc::TWIST_END, twist);
calcp->setVar(LLCalc::TWIST_BEGIN, twist_begin);
// Shear
F32 shear_x = volume_params.getShearX();
F32 shear_y = volume_params.getShearY();
mSpinShearX->set( shear_x );
mSpinShearY->set( shear_y );
calcp->setVar(LLCalc::X_SHEAR, shear_x);
calcp->setVar(LLCalc::Y_SHEAR, shear_y);
// Taper
F32 taper_x = volume_params.getTaperX();
F32 taper_y = volume_params.getTaperY();
mSpinTaperX->set( taper_x );
mSpinTaperY->set( taper_y );
calcp->setVar(LLCalc::X_TAPER, taper_x);
calcp->setVar(LLCalc::Y_TAPER, taper_y);
// Radius offset.
F32 radius_offset = volume_params.getRadiusOffset();
// Limit radius offset, based on taper and hole size y.
/* DISREGARD THAT LET'S GET CRAZY -HgB
F32 radius_mag = fabs(radius_offset);
F32 hole_y_mag = fabs(scale_y);
F32 taper_y_mag = fabs(taper_y);
// Check to see if the taper effects us.
if ( (radius_offset > 0.f && taper_y < 0.f) ||
(radius_offset < 0.f && taper_y > 0.f) )
{
// The taper does not help increase the radius offset range.
taper_y_mag = 0.f;
}
F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
// Enforce the maximum magnitude.
if (radius_mag > max_radius_mag)
{
// Check radius offset sign.
if (radius_offset < 0.f)
{
radius_offset = -max_radius_mag;
}
else
{
radius_offset = max_radius_mag;
}
}
*/
mSpinRadiusOffset->set( radius_offset);
calcp->setVar(LLCalc::RADIUS_OFFSET, radius_offset);
// Revolutions
F32 revolutions = volume_params.getRevolutions();
mSpinRevolutions->set( revolutions );
calcp->setVar(LLCalc::REVOLUTIONS, revolutions);
// Skew
F32 skew = volume_params.getSkew();
// Limit skew, based on revolutions hole size x.
/* SUCKS... NEVER MIND -HgB
F32 skew_mag= fabs(skew);
F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
// Discontinuity; A revolution of 1 allows skews below 0.5.
if ( fabs(revolutions - 1.0f) < 0.001)
min_skew_mag = 0.0f;
// Clip skew.
if (skew_mag < min_skew_mag)
{
// Check skew sign.
if (skew < 0.0f)
{
skew = -min_skew_mag;
}
else
{
skew = min_skew_mag;
}
}
*/
mSpinSkew->set( skew );
calcp->setVar(LLCalc::SKEW, skew);
}
// Compute control visibility, label names, and twist range.
// Start with defaults.
BOOL cut_visible = TRUE;
BOOL hollow_visible = TRUE;
BOOL top_size_x_visible = TRUE;
BOOL top_size_y_visible = TRUE;
BOOL top_shear_x_visible = TRUE;
BOOL top_shear_y_visible = TRUE;
BOOL twist_visible = TRUE;
// <edit>
// Enable advanced cut (aka dimple, aka path, aka profile cut) for everything
//BOOL advanced_cut_visible = FALSE;
BOOL advanced_cut_visible = TRUE;
// </edit>
BOOL taper_visible = FALSE;
BOOL skew_visible = FALSE;
BOOL radius_offset_visible = FALSE;
BOOL revolutions_visible = FALSE;
BOOL sculpt_texture_visible = FALSE;
F32 twist_min = OBJECT_TWIST_LINEAR_MIN;
F32 twist_max = OBJECT_TWIST_LINEAR_MAX;
F32 twist_inc = OBJECT_TWIST_LINEAR_INC;
BOOL advanced_is_dimple = FALSE;
BOOL advanced_is_slice = FALSE;
BOOL size_is_hole = FALSE;
// Tune based on overall volume type
switch (selected_item)
{
case MI_SPHERE:
// <edit>
case MI_SPIRAL_CIRCLE:
case MI_SPIRAL_SQUARE:
case MI_SPIRAL_TRIANGLE:
case MI_SPIRAL_SEMICIRCLE:
//top_size_x_visible = FALSE;
//top_size_y_visible = FALSE;
//top_shear_x_visible = FALSE;
//top_shear_y_visible = FALSE;
//advanced_cut_visible = TRUE;
advanced_is_dimple = TRUE;
//twist_min = OBJECT_TWIST_MIN;
//twist_max = OBJECT_TWIST_MAX;
//twist_inc = OBJECT_TWIST_INC;
// Just like the others except no radius
size_is_hole = TRUE;
skew_visible = TRUE;
//advanced_cut_visible = TRUE;
taper_visible = TRUE;
radius_offset_visible = FALSE;
revolutions_visible = TRUE;
twist_min = OBJECT_TWIST_MIN;
twist_max = OBJECT_TWIST_MAX;
twist_inc = OBJECT_TWIST_INC;
break;
case MI_TEST_BOX:
case MI_TEST_CYLINDER:
case MI_TEST_PRISM:
case MI_TEST_HEMICYLINDER:
cut_visible = FALSE;
//advanced_cut_visible = TRUE;
advanced_is_slice = TRUE;
//taper_visible = FALSE;
radius_offset_visible = FALSE;
revolutions_visible = FALSE;
top_shear_x_visible = FALSE;
top_shear_y_visible = FALSE;
twist_min = OBJECT_TWIST_MIN;
twist_max = OBJECT_TWIST_MAX;
twist_inc = OBJECT_TWIST_INC;
// </edit>
break;
case MI_TORUS:
case MI_TUBE:
case MI_RING:
//top_size_x_visible = FALSE;
//top_size_y_visible = FALSE;
size_is_hole = TRUE;
skew_visible = TRUE;
advanced_cut_visible = TRUE;
taper_visible = TRUE;
radius_offset_visible = TRUE;
revolutions_visible = TRUE;
twist_min = OBJECT_TWIST_MIN;
twist_max = OBJECT_TWIST_MAX;
twist_inc = OBJECT_TWIST_INC;
break;
case MI_SCULPT:
cut_visible = FALSE;
hollow_visible = FALSE;
twist_visible = FALSE;
top_size_x_visible = FALSE;
top_size_y_visible = FALSE;
top_shear_x_visible = FALSE;
top_shear_y_visible = FALSE;
skew_visible = FALSE;
advanced_cut_visible = FALSE;
taper_visible = FALSE;
radius_offset_visible = FALSE;
revolutions_visible = FALSE;
sculpt_texture_visible = TRUE;
break;
case MI_BOX:
advanced_cut_visible = TRUE;
advanced_is_slice = TRUE;
break;
case MI_CYLINDER:
advanced_cut_visible = TRUE;
advanced_is_slice = TRUE;
break;
case MI_PRISM:
advanced_cut_visible = TRUE;
advanced_is_slice = TRUE;
break;
default:
break;
}
// Check if we need to change top size/hole size params.
switch (selected_item)
{
// <edit>
//case MI_SPHERE:
// Sphere fall through to default: set scale_x min/max, dunno why
// </edit>
case MI_TORUS:
case MI_TUBE:
case MI_RING:
mSpinScaleX->set( scale_x );
mSpinScaleY->set( scale_y );
calcp->setVar(LLCalc::X_HOLE, scale_x);
calcp->setVar(LLCalc::Y_HOLE, scale_y);
mSpinScaleX->setMinValue(gHippoLimits->getMinHoleSize());
mSpinScaleX->setMaxValue(OBJECT_MAX_HOLE_SIZE_X);
mSpinScaleY->setMinValue(gHippoLimits->getMinHoleSize());
mSpinScaleY->setMaxValue(OBJECT_MAX_HOLE_SIZE_Y);
break;
default:
if (editable)
{
mSpinScaleX->set( 1.f - scale_x );
mSpinScaleY->set( 1.f - scale_y );
mSpinScaleX->setMinValue(-1.f);
mSpinScaleX->setMaxValue(1.f);
mSpinScaleY->setMinValue(-1.f);
mSpinScaleY->setMaxValue(1.f);
// Torus' Hole Size is Box/Cyl/Prism's Taper
calcp->setVar(LLCalc::X_TAPER, 1.f - scale_x);
calcp->setVar(LLCalc::Y_TAPER, 1.f - scale_y);
// Box/Cyl/Prism have no hole size
calcp->setVar(LLCalc::X_HOLE, scale_x);
calcp->setVar(LLCalc::Y_HOLE, scale_y);
}
break;
}
// Check if we need to limit the hollow based on the hole type.
/* NO, GO NUTS -HgB
if ( selected_hole == MI_HOLE_SQUARE &&
( selected_item == MI_CYLINDER || selected_item == MI_TORUS ||
selected_item == MI_PRISM || selected_item == MI_RING ||
selected_item == MI_SPHERE ) )
{
mSpinHollow->setMinValue(0.f);
mSpinHollow->setMaxValue(70.f);
}
else
*/
{
mSpinHollow->setMinValue(0.f);
mSpinHollow->setMaxValue(gHippoLimits->getMaxHollow() * 100.0f);
}
// Update field enablement
mLabelBaseType ->setEnabled( enabled );
mComboBaseType ->setEnabled( enabled );
mLabelCut ->setEnabled( enabled );
mSpinCutBegin ->setEnabled( enabled );
mSpinCutEnd ->setEnabled( enabled );
mLabelHollow ->setEnabled( enabled );
mSpinHollow ->setEnabled( enabled );
mLabelHoleType ->setEnabled( hole_enabled );
mComboHoleType ->setEnabled( hole_enabled );
mLabelTwist ->setEnabled( enabled );
mSpinTwist ->setEnabled( enabled );
mSpinTwistBegin ->setEnabled( enabled );
mLabelSkew ->setEnabled( enabled );
mSpinSkew ->setEnabled( enabled );
childSetVisible("scale_hole", FALSE);
childSetVisible("scale_taper", FALSE);
if (top_size_x_visible || top_size_y_visible)
{
if (size_is_hole)
{
childSetVisible("scale_hole", TRUE);
childSetEnabled("scale_hole", enabled);
}
else
{
childSetVisible("scale_taper", TRUE);
childSetEnabled("scale_taper", enabled);
}
}
mSpinScaleX ->setEnabled( enabled );
mSpinScaleY ->setEnabled( enabled );
mLabelShear ->setEnabled( enabled );
mSpinShearX ->setEnabled( enabled );
mSpinShearY ->setEnabled( enabled );
childSetVisible("advanced_cut", FALSE);
childSetVisible("advanced_dimple", FALSE);
childSetVisible("advanced_slice", FALSE);
if (advanced_cut_visible)
{
if (advanced_is_dimple)
{
childSetVisible("advanced_dimple", TRUE);
childSetEnabled("advanced_dimple", enabled);
}
else if (advanced_is_slice)
{
childSetVisible("advanced_slice", TRUE);
childSetEnabled("advanced_slice", enabled);
}
else
{
childSetVisible("advanced_cut", TRUE);
childSetEnabled("advanced_cut", enabled);
}
}
mCtrlPathBegin ->setEnabled( enabled );
mCtrlPathEnd ->setEnabled( enabled );
mLabelTaper ->setEnabled( enabled );
mSpinTaperX ->setEnabled( enabled );
mSpinTaperY ->setEnabled( enabled );
mLabelRadiusOffset->setEnabled( enabled );
mSpinRadiusOffset ->setEnabled( enabled );
mLabelRevolutions->setEnabled( enabled );
mSpinRevolutions ->setEnabled( enabled );
// Update field visibility
mLabelCut ->setVisible( cut_visible );
mSpinCutBegin ->setVisible( cut_visible );
mSpinCutEnd ->setVisible( cut_visible );
mLabelHollow ->setVisible( hollow_visible );
mSpinHollow ->setVisible( hollow_visible );
mLabelHoleType ->setVisible( hollow_visible );
mComboHoleType ->setVisible( hollow_visible );
mLabelTwist ->setVisible( twist_visible );
mSpinTwist ->setVisible( twist_visible );
mSpinTwistBegin ->setVisible( twist_visible );
mSpinTwist ->setMinValue( twist_min );
mSpinTwist ->setMaxValue( twist_max );
mSpinTwist ->setIncrement( twist_inc );
mSpinTwistBegin ->setMinValue( twist_min );
mSpinTwistBegin ->setMaxValue( twist_max );
mSpinTwistBegin ->setIncrement( twist_inc );
mSpinScaleX ->setVisible( top_size_x_visible );
mSpinScaleY ->setVisible( top_size_y_visible );
mLabelSkew ->setVisible( skew_visible );
mSpinSkew ->setVisible( skew_visible );
mLabelShear ->setVisible( top_shear_x_visible || top_shear_y_visible );
mSpinShearX ->setVisible( top_shear_x_visible );
mSpinShearY ->setVisible( top_shear_y_visible );
mCtrlPathBegin ->setVisible( advanced_cut_visible );
mCtrlPathEnd ->setVisible( advanced_cut_visible );
mLabelTaper ->setVisible( taper_visible );
mSpinTaperX ->setVisible( taper_visible );
mSpinTaperY ->setVisible( taper_visible );
mLabelRadiusOffset->setVisible( radius_offset_visible );
mSpinRadiusOffset ->setVisible( radius_offset_visible );
mLabelRevolutions->setVisible( revolutions_visible );
mSpinRevolutions ->setVisible( revolutions_visible );
mCtrlSculptTexture->setVisible(sculpt_texture_visible);
mLabelSculptType->setVisible(sculpt_texture_visible);
mCtrlSculptType->setVisible(sculpt_texture_visible);
// sculpt texture
if (selected_item == MI_SCULPT)
{
LLUUID id;
const LLSculptParams *sculpt_params = objectp->getSculptParams();
if (sculpt_params) // if we have a legal sculpt param block for this object:
{
if (mObject != objectp) // we've just selected a new object, so save for undo
{
mSculptTextureRevert = sculpt_params->getSculptTexture();
mSculptTypeRevert = sculpt_params->getSculptType();
}
U8 sculpt_type = sculpt_params->getSculptType();
U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
isMesh = (sculpt_stitching == LL_SCULPT_TYPE_MESH);
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if(mTextureCtrl)
{
mTextureCtrl->setTentative(FALSE);
mTextureCtrl->setEnabled(editable && !isMesh);
if (editable)
mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture());
else
mTextureCtrl->setImageAssetID(LLUUID::null);
}
mComboBaseType->setEnabled(!isMesh);
if (mCtrlSculptType)
{
mCtrlSculptType->setCurrentByIndex(sculpt_stitching);
mCtrlSculptType->setEnabled(editable && !isMesh);
}
if (mCtrlSculptMirror)
{
mCtrlSculptMirror->set(sculpt_mirror);
mCtrlSculptMirror->setEnabled(editable && !isMesh);
}
if (mCtrlSculptInvert)
{
mCtrlSculptInvert->set(sculpt_invert);
mCtrlSculptInvert->setEnabled(editable);
}
if (mLabelSculptType)
{
mLabelSculptType->setEnabled(TRUE);
}
}
}
else
{
mSculptTextureRevert = LLUUID::null;
}
mCtrlSculptMirror->setVisible(sculpt_texture_visible && !isMesh);
mCtrlSculptInvert->setVisible(sculpt_texture_visible && !isMesh);
//----------------------------------------------------------------------------
mObject = objectp;
mRootObject = root_objectp;
}
// static
bool LLPanelObject::precommitValidate( const LLSD& data )
{
// TODO: Richard will fill this in later.
return TRUE; // FALSE means that validation failed and new value should not be commited.
}
void LLPanelObject::sendIsPhysical()
{
BOOL value = mCheckPhysics->get();
if( mIsPhysical != value )
{
LLSelectMgr::getInstance()->selectionUpdatePhysics(value);
mIsPhysical = value;
LL_INFOS() << "update physics sent" << LL_ENDL;
}
else
{
LL_INFOS() << "update physics not changed" << LL_ENDL;
}
}
void LLPanelObject::sendIsTemporary()
{
BOOL value = mCheckTemporary->get();
if( mIsTemporary != value )
{
LLSelectMgr::getInstance()->selectionUpdateTemporary(value);
mIsTemporary = value;
LL_INFOS() << "update temporary sent" << LL_ENDL;
}
else
{
LL_INFOS() << "update temporary not changed" << LL_ENDL;
}
}
void LLPanelObject::sendIsPhantom()
{
BOOL value = mCheckPhantom->get();
if( mIsPhantom != value )
{
LLSelectMgr::getInstance()->selectionUpdatePhantom(value);
mIsPhantom = value;
LL_INFOS() << "update phantom sent" << LL_ENDL;
}
else
{
LL_INFOS() << "update phantom not changed" << LL_ENDL;
}
}
// static
void LLPanelObject::onCommitMaterial( LLUICtrl* ctrl, void* userdata )
{
//LLPanelObject* self = (LLPanelObject*) userdata;
LLComboBox* box = (LLComboBox*) ctrl;
if (box)
{
// apply the currently selected material to the object
const std::string& material_name = box->getSimple();
if (material_name != LEGACY_FULLBRIGHT_DESC)
{
U8 material_code = LLMaterialTable::basic.getMCode(material_name);
LLSelectMgr::getInstance()->selectionSetMaterial(material_code);
}
}
}
// static
void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
if (self->mObject.isNull())
{
return;
}
if (self->mObject->getPCode() != LL_PCODE_VOLUME)
{
// Don't allow modification of non-volume objects.
return;
}
LLVolume *volume = self->mObject->getVolume();
if (!volume)
{
return;
}
LLVolumeParams volume_params;
self->getVolumeParams(volume_params);
// set sculpting
S32 selected_type = self->mComboBaseType->getCurrentIndex();
if (selected_type == MI_SCULPT)
{
self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE);
const LLSculptParams *sculpt_params = self->mObject->getSculptParams();
if (sculpt_params)
volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType());
}
else
{
const LLSculptParams *sculpt_params = self->mObject->getSculptParams();
if (sculpt_params)
self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE);
}
// Update the volume, if necessary.
self->mObject->updateVolume(volume_params);
// This was added to make sure thate when changes are made, the UI
// adjusts to present valid options.
// *FIX: only some changes, ie, hollow or primitive type changes,
// require a refresh.
self->refresh();
}
void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
{
// Figure out what type of volume to make
S32 was_selected_type = mSelectedType;
S32 selected_type = mComboBaseType->getCurrentIndex();
mComboBaseType->getValue();
U8 profile;
U8 path;
switch ( selected_type )
{
case MI_CYLINDER:
profile = LL_PCODE_PROFILE_CIRCLE;
path = LL_PCODE_PATH_LINE;
break;
case MI_BOX:
profile = LL_PCODE_PROFILE_SQUARE;
path = LL_PCODE_PATH_LINE;
break;
case MI_PRISM:
profile = LL_PCODE_PROFILE_EQUALTRI;
path = LL_PCODE_PATH_LINE;
break;
case MI_SPHERE:
profile = LL_PCODE_PROFILE_CIRCLE_HALF;
path = LL_PCODE_PATH_CIRCLE;
break;
case MI_TORUS:
profile = LL_PCODE_PROFILE_CIRCLE;
path = LL_PCODE_PATH_CIRCLE;
break;
case MI_TUBE:
profile = LL_PCODE_PROFILE_SQUARE;
path = LL_PCODE_PATH_CIRCLE;
break;
case MI_RING:
profile = LL_PCODE_PROFILE_EQUALTRI;
path = LL_PCODE_PATH_CIRCLE;
break;
case MI_SCULPT:
profile = LL_PCODE_PROFILE_CIRCLE;
path = LL_PCODE_PATH_CIRCLE;
break;
// <edit>
case MI_HEMICYLINDER:
profile = LL_PCODE_PROFILE_CIRCLE_HALF;
path = LL_PCODE_PATH_LINE;
break;
// Spirals
case MI_SPIRAL_CIRCLE:
profile = LL_PCODE_PROFILE_CIRCLE;
path = LL_PCODE_PATH_CIRCLE2;
break;
case MI_SPIRAL_SQUARE:
profile = LL_PCODE_PROFILE_SQUARE;
path = LL_PCODE_PATH_CIRCLE2;
break;
case MI_SPIRAL_TRIANGLE:
profile = LL_PCODE_PROFILE_EQUALTRI;
path = LL_PCODE_PATH_CIRCLE2;
break;
case MI_SPIRAL_SEMICIRCLE:
profile = LL_PCODE_PROFILE_CIRCLE_HALF;
path = LL_PCODE_PATH_CIRCLE2;
break;
// Test path
case MI_TEST_CYLINDER:
profile = LL_PCODE_PROFILE_CIRCLE;
path = LL_PCODE_PATH_TEST;
break;
case MI_TEST_BOX:
profile = LL_PCODE_PROFILE_SQUARE;
path = LL_PCODE_PATH_TEST;
break;
case MI_TEST_PRISM:
profile = LL_PCODE_PROFILE_EQUALTRI;
path = LL_PCODE_PATH_TEST;
break;
case MI_TEST_HEMICYLINDER:
profile = LL_PCODE_PROFILE_CIRCLE_HALF;
path = LL_PCODE_PATH_TEST;
break;
// </edit>
default:
LL_WARNS() << "Unknown base type " << selected_type
<< " in getVolumeParams()" << LL_ENDL;
// assume a box
selected_type = MI_BOX;
profile = LL_PCODE_PROFILE_SQUARE;
path = LL_PCODE_PATH_LINE;
break;
}
if (path == LL_PCODE_PATH_LINE)
{
LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject);
if (volobjp->isFlexible())
{
path = LL_PCODE_PATH_FLEXIBLE;
}
}
S32 selected_hole = mComboHoleType->getCurrentIndex();
U8 hole;
switch (selected_hole)
{
case MI_HOLE_CIRCLE:
hole = LL_PCODE_HOLE_CIRCLE;
break;
case MI_HOLE_SQUARE:
hole = LL_PCODE_HOLE_SQUARE;
break;
case MI_HOLE_TRIANGLE:
hole = LL_PCODE_HOLE_TRIANGLE;
break;
case MI_HOLE_SAME:
default:
hole = LL_PCODE_HOLE_SAME;
break;
}
volume_params.setType(profile | hole, path);
mSelectedType = selected_type;
// Compute cut start/end
F32 cut_begin = mSpinCutBegin->get();
F32 cut_end = mSpinCutEnd->get();
// Make sure at least OBJECT_CUT_INC of the object survives
if (cut_begin > cut_end - OBJECT_MIN_CUT_INC)
{
cut_begin = cut_end - OBJECT_MIN_CUT_INC;
mSpinCutBegin->set(cut_begin);
}
F32 adv_cut_begin = mCtrlPathBegin->get();
F32 adv_cut_end = mCtrlPathEnd->get();
// Make sure at least OBJECT_CUT_INC of the object survives
if (adv_cut_begin > adv_cut_end - OBJECT_MIN_CUT_INC)
{
adv_cut_begin = adv_cut_end - OBJECT_MIN_CUT_INC;
mCtrlPathBegin->set(adv_cut_begin);
}
F32 begin_s, end_s;
F32 begin_t, end_t;
// <edit>
//if (selected_type == MI_SPHERE || selected_type == MI_TORUS ||
// selected_type == MI_TUBE || selected_type == MI_RING)
BOOL linear_path = (path == LL_PCODE_PATH_LINE) ||
(path == LL_PCODE_PATH_FLEXIBLE);
if(!linear_path)
// </edit>
{
begin_s = adv_cut_begin;
end_s = adv_cut_end;
begin_t = cut_begin;
end_t = cut_end;
}
else
{
begin_s = cut_begin;
end_s = cut_end;
begin_t = adv_cut_begin;
end_t = adv_cut_end;
}
volume_params.setBeginAndEndS(begin_s, end_s);
volume_params.setBeginAndEndT(begin_t, end_t);
// Hollowness
F32 hollow = mSpinHollow->get() / 100.f;
/* DUTCH PORN MODE -HgB
if ( selected_hole == MI_HOLE_SQUARE &&
( selected_type == MI_CYLINDER || selected_type == MI_TORUS ||
selected_type == MI_PRISM || selected_type == MI_RING ||
selected_type == MI_SPHERE ) )
{
if (hollow > 0.7f) hollow = 0.7f;
}
*/
volume_params.setHollow( hollow );
// Twist Begin,End
F32 twist_begin = mSpinTwistBegin->get();
F32 twist = mSpinTwist->get();
// Check the path type for twist conversion.
if (path == LL_PCODE_PATH_LINE || path == LL_PCODE_PATH_FLEXIBLE)
{
twist_begin /= OBJECT_TWIST_LINEAR_MAX;
twist /= OBJECT_TWIST_LINEAR_MAX;
}
else
{
twist_begin /= OBJECT_TWIST_MAX;
twist /= OBJECT_TWIST_MAX;
}
volume_params.setTwistBegin(twist_begin);
volume_params.setTwist(twist);
// Scale X,Y
F32 scale_x = mSpinScaleX->get();
F32 scale_y = mSpinScaleY->get();
// <edit>
//if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM)
if ( was_selected_type == MI_BOX || was_selected_type == MI_CYLINDER || was_selected_type == MI_PRISM ||
was_selected_type == MI_SPHERE ||
was_selected_type == MI_HEMICYLINDER ||
was_selected_type == MI_SPIRAL_CIRCLE ||
was_selected_type == MI_SPIRAL_SQUARE ||
was_selected_type == MI_SPIRAL_TRIANGLE ||
was_selected_type == MI_SPIRAL_SEMICIRCLE ||
was_selected_type == MI_TEST_BOX ||
was_selected_type == MI_TEST_PRISM ||
was_selected_type == MI_TEST_CYLINDER ||
was_selected_type == MI_TEST_HEMICYLINDER
)
// but why put sphere here if the other circle-paths aren't?
// </edit>
{
scale_x = 1.f - scale_x;
scale_y = 1.f - scale_y;
}
// Skew
F32 skew = mSpinSkew->get();
// Taper X,Y
F32 taper_x = mSpinTaperX->get();
F32 taper_y = mSpinTaperY->get();
// Radius offset
F32 radius_offset = mSpinRadiusOffset->get();
// Revolutions
F32 revolutions = mSpinRevolutions->get();
if ( selected_type == MI_SPHERE )
{
// Snap values to valid sphere parameters.
// make scale (taper (hole size?)) work for sphere, part 2 of 2
//scale_x = 1.0f;
//scale_y = 1.0f;
// </edit>
// <edit> testing skew
//skew = 0.0f;
// </edit>
// <edit>
// Make OTHER taper work for sphere
//taper_x = 0.0f;
//taper_y = 0.0f;
// </edit>
radius_offset = 0.0f;
// <edit>
// Revolutions works fine on sphere
//revolutions = 1.0f;
// </edit>
}
else if ( selected_type == MI_TORUS || selected_type == MI_TUBE ||
selected_type == MI_RING )
{
scale_x = llclamp(
scale_x,
gHippoLimits->getMinHoleSize(),
OBJECT_MAX_HOLE_SIZE_X);
scale_y = llclamp(
scale_y,
gHippoLimits->getMinHoleSize(),
OBJECT_MAX_HOLE_SIZE_Y);
// Limit radius offset, based on taper and hole size y.
F32 radius_mag = fabs(radius_offset);
F32 hole_y_mag = fabs(scale_y);
F32 taper_y_mag = fabs(taper_y);
// Check to see if the taper effects us.
if ( (radius_offset > 0.f && taper_y < 0.f) ||
(radius_offset < 0.f && taper_y > 0.f) )
{
// The taper does not help increase the radius offset range.
taper_y_mag = 0.f;
}
F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
// Enforce the maximum magnitude.
if (radius_mag > max_radius_mag)
{
// Check radius offset sign.
if (radius_offset < 0.f)
{
radius_offset = -max_radius_mag;
}
else
{
radius_offset = max_radius_mag;
}
}
// Check the skew value against the revolutions.
F32 skew_mag= fabs(skew);
F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
// Discontinuity; A revolution of 1 allows skews below 0.5.
if ( fabs(revolutions - 1.0f) < 0.001)
min_skew_mag = 0.0f;
// Clip skew.
if (skew_mag < min_skew_mag)
{
// Check skew sign.
if (skew < 0.0f)
{
skew = -min_skew_mag;
}
else
{
skew = min_skew_mag;
}
}
}
volume_params.setRatio( scale_x, scale_y );
volume_params.setSkew(skew);
volume_params.setTaper( taper_x, taper_y );
volume_params.setRadiusOffset(radius_offset);
volume_params.setRevolutions(revolutions);
// Shear X,Y
F32 shear_x = mSpinShearX->get();
F32 shear_y = mSpinShearY->get();
volume_params.setShear( shear_x, shear_y );
if (selected_type == MI_SCULPT)
{
volume_params.setSculptID(LLUUID::null, 0);
volume_params.setBeginAndEndT (0, 1);
volume_params.setBeginAndEndS (0, 1);
volume_params.setHollow (0);
volume_params.setTwistBegin (0);
volume_params.setTwistEnd (0);
volume_params.setRatio (1, 0.5);
volume_params.setShear (0, 0);
volume_params.setTaper (0, 0);
volume_params.setRevolutions (1);
volume_params.setRadiusOffset (0);
volume_params.setSkew (0);
}
}
// BUG: Make work with multiple objects
void LLPanelObject::sendRotation(BOOL btn_down)
{
if (mObject.isNull()) return;
LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
new_rot.mV[VX] = ll_round(new_rot.mV[VX], OBJECT_ROTATION_PRECISION);
new_rot.mV[VY] = ll_round(new_rot.mV[VY], OBJECT_ROTATION_PRECISION);
new_rot.mV[VZ] = ll_round(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION);
// Note: must compare before conversion to radians
LLVector3 delta = new_rot - mCurEulerDegrees;
if (delta.magVec() >= 0.0005f)
{
mCurEulerDegrees = new_rot;
new_rot *= DEG_TO_RAD;
LLQuaternion rotation;
rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]);
if (mRootObject != mObject)
{
rotation = rotation * ~mRootObject->getRotationRegion();
}
std::vector<LLVector3>& child_positions = mObject->mUnselectedChildrenPositions ;
std::vector<LLQuaternion> child_rotations;
if (mObject->isRootEdit())
{
mObject->saveUnselectedChildrenRotation(child_rotations) ;
mObject->saveUnselectedChildrenPosition(child_positions) ;
}
mObject->setRotation(rotation);
LLManip::rebuild(mObject) ;
// for individually selected roots, we need to counterrotate all the children
if (mObject->isRootEdit())
{
mObject->resetChildrenRotationAndPosition(child_rotations, child_positions) ;
}
if(!btn_down)
{
child_positions.clear() ;
LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_ROTATION | UPD_POSITION);
}
}
}
// BUG: Make work with multiple objects
void LLPanelObject::sendScale(BOOL btn_down)
{
if (mObject.isNull()) return;
LLVector3 newscale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
LLVector3 delta = newscale - mObject->getScale();
//Saw this changed in some viewers to be more touchy than this, but it would likely cause more updates and higher lag for the client. -HgB
if (delta.magVec() >= 0.0001f) //CF: just a bit more touchy
{
// scale changed by more than 1/10 millimeter
// check to see if we aren't scaling the textures
// (in which case the tex coord's need to be recomputed)
BOOL dont_stretch_textures = !LLManipScale::getStretchTextures();
if (dont_stretch_textures)
{
LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_SCALE);
}
mObject->setScale(newscale, TRUE);
if(!btn_down)
{
LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_SCALE | UPD_POSITION);
}
LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, !dont_stretch_textures);
// LL_INFOS() << "scale sent" << LL_ENDL;
}
else
{
// LL_INFOS() << "scale not changed" << LL_ENDL;
}
}
void LLPanelObject::sendPosition(BOOL btn_down)
{
if (mObject.isNull()) return;
LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
LLViewerRegion* regionp = mObject->getRegion();
// Clamp the Z height
const F32 height = newpos.mV[VZ];
const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal());
// <edit>
//const F32 max_height = LLWorld::getInstance()->getRegionMaxHeight();
const F32 max_height = F32(340282346638528859811704183484516925440.0f);
// </edit>
if (!mObject->isAttachment())
{
if ( height < min_height)
{
newpos.mV[VZ] = min_height;
mCtrlPosZ->set( min_height );
}
else if ( height > max_height )
{
newpos.mV[VZ] = max_height;
mCtrlPosZ->set( max_height );
}
// Grass is always drawn on the ground, so clamp its position to the ground
if (mObject->getPCode() == LL_PCODE_LEGACY_GRASS)
{
mCtrlPosZ->set(LLWorld::getInstance()->resolveLandHeightAgent(newpos) + 1.f);
}
}
// Make sure new position is in a valid region, so the object
// won't get dumped by the simulator.
LLVector3d new_pos_global = regionp->getPosGlobalFromRegion(newpos);
if (LLWorld::getInstance()->positionRegionValidGlobal(new_pos_global) ||
mObject->isAttachment())
{
// send only if the position is changed, that is, the delta vector is not zero
LLVector3d old_pos_global = mObject->getPositionGlobal();
LLVector3d delta = new_pos_global - old_pos_global;
// moved more than 1/10 millimeter
//Saw this changed in some viewers to be more touchy than this, but it would likely cause more updates and higher lag for the client. -HgB
if (delta.magVec() >= 0.0001f) //CF: just a bit more touchy
{
if (mRootObject != mObject)
{
newpos = newpos - mRootObject->getPositionRegion();
newpos = newpos * ~mRootObject->getRotationRegion();
mObject->setPositionParent(newpos);
}
else
{
mObject->setPositionEdit(newpos);
}
LLManip::rebuild(mObject) ;
// for individually selected roots, we need to counter-translate all unselected children
if (mObject->isRootEdit())
{
// only offset by parent's translation
mObject->resetChildrenPosition(LLVector3(-delta), TRUE) ;
}
if(!btn_down)
{
LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
}
LLSelectMgr::getInstance()->updateSelectionCenter();
}
}
else
{
// move failed, so we update the UI with the correct values
LLVector3 vec = mRootObject->getPositionRegion();
mCtrlPosX->set(vec.mV[VX]);
mCtrlPosY->set(vec.mV[VY]);
mCtrlPosZ->set(vec.mV[VZ]);
}
}
void LLPanelObject::sendSculpt()
{
if (mObject.isNull())
return;
LLSculptParams sculpt_params;
LLUUID sculpt_id = LLUUID::null;
if (mCtrlSculptTexture)
sculpt_id = mCtrlSculptTexture->getImageAssetID();
U8 sculpt_type = 0;
if (mCtrlSculptType)
sculpt_type |= mCtrlSculptType->getCurrentIndex();
bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH;
if (mCtrlSculptMirror)
{
mCtrlSculptMirror->setEnabled(enabled ? TRUE : FALSE);
}
if (mCtrlSculptInvert)
{
mCtrlSculptInvert->setEnabled(enabled ? TRUE : FALSE);
}
if ((mCtrlSculptMirror) && (mCtrlSculptMirror->get()))
sculpt_type |= LL_SCULPT_FLAG_MIRROR;
if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get()))
sculpt_type |= LL_SCULPT_FLAG_INVERT;
sculpt_params.setSculptTexture(sculpt_id, sculpt_type);
mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
}
void LLPanelObject::refresh()
{
getState();
if (mObject.notNull() && mObject->isDead())
{
mObject = NULL;
}
if (mRootObject.notNull() && mRootObject->isDead())
{
mRootObject = NULL;
}
}
void LLPanelObject::draw()
{
const LLColor4 white( 1.0f, 1.0f, 1.0f, 1);
const LLColor4 red( 1.0f, 0.25f, 0.f, 1);
const LLColor4 green( 0.f, 1.0f, 0.f, 1);
const LLColor4 blue( 0.f, 0.5f, 1.0f, 1);
// Tune the colors of the labels
LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
if (tool == LLToolCompTranslate::getInstance())
{
mCtrlPosX ->setLabelColor(red);
mCtrlPosY ->setLabelColor(green);
mCtrlPosZ ->setLabelColor(blue);
mCtrlScaleX ->setLabelColor(white);
mCtrlScaleY ->setLabelColor(white);
mCtrlScaleZ ->setLabelColor(white);
mCtrlRotX ->setLabelColor(white);
mCtrlRotY ->setLabelColor(white);
mCtrlRotZ ->setLabelColor(white);
}
else if ( tool == LLToolCompScale::getInstance() )
{
mCtrlPosX ->setLabelColor(white);
mCtrlPosY ->setLabelColor(white);
mCtrlPosZ ->setLabelColor(white);
mCtrlScaleX ->setLabelColor(red);
mCtrlScaleY ->setLabelColor(green);
mCtrlScaleZ ->setLabelColor(blue);
mCtrlRotX ->setLabelColor(white);
mCtrlRotY ->setLabelColor(white);
mCtrlRotZ ->setLabelColor(white);
}
else if ( tool == LLToolCompRotate::getInstance() )
{
mCtrlPosX ->setLabelColor(white);
mCtrlPosY ->setLabelColor(white);
mCtrlPosZ ->setLabelColor(white);
mCtrlScaleX ->setLabelColor(white);
mCtrlScaleY ->setLabelColor(white);
mCtrlScaleZ ->setLabelColor(white);
mCtrlRotX ->setLabelColor(red);
mCtrlRotY ->setLabelColor(green);
mCtrlRotZ ->setLabelColor(blue);
}
else
{
mCtrlPosX ->setLabelColor(white);
mCtrlPosY ->setLabelColor(white);
mCtrlPosZ ->setLabelColor(white);
mCtrlScaleX ->setLabelColor(white);
mCtrlScaleY ->setLabelColor(white);
mCtrlScaleZ ->setLabelColor(white);
mCtrlRotX ->setLabelColor(white);
mCtrlRotY ->setLabelColor(white);
mCtrlRotZ ->setLabelColor(white);
}
LLPanel::draw();
}
//
// Static functions
//
// static
void LLPanelObject::onCommitLock(LLUICtrl *ctrl, void *data)
{
// Checkbox will have toggled itself
LLPanelObject *self = (LLPanelObject *)data;
if(self->mRootObject.isNull()) return;
BOOL new_state = self->mCheckLock->get();
LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, !new_state, PERM_MOVE | PERM_MODIFY);
}
// static
void LLPanelObject::onCommitPosition( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
self->sendPosition(btn_down);
}
// static
void LLPanelObject::onCommitScale( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
self->sendScale(btn_down);
}
// static
void LLPanelObject::onCommitRotation( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
BOOL btn_down = ((LLSpinCtrl*)ctrl)->isMouseHeldDown() ;
self->sendRotation(btn_down);
// Needed to ensure all rotations are shown consistently in range
self->refresh();
}
// static
void LLPanelObject::onCommitPhysics( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
self->sendIsPhysical();
}
// static
void LLPanelObject::onCommitTemporary( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
self->sendIsTemporary();
}
// static
void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata )
{
LLPanelObject* self = (LLPanelObject*) userdata;
self->sendIsPhantom();
}
void LLPanelObject::onSelectSculpt(const LLSD& data)
{
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if (mTextureCtrl)
{
mSculptTextureRevert = mTextureCtrl->getImageAssetID();
}
sendSculpt();
}
void LLPanelObject::onCommitSculpt( const LLSD& data )
{
sendSculpt();
}
BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item)
{
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if (mTextureCtrl)
{
LLUUID asset = item->getAssetUUID();
mTextureCtrl->setImageAssetID(asset);
mSculptTextureRevert = asset;
}
return TRUE;
}
void LLPanelObject::onCancelSculpt(const LLSD& data)
{
LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control");
if(!mTextureCtrl)
return;
mTextureCtrl->setImageAssetID(mSculptTextureRevert);
sendSculpt();
}
// static
void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata)
{
LLPanelObject* self = (LLPanelObject*) userdata;
self->sendSculpt();
}
// static
void LLPanelObject::onClickBuildConstants(void *)
{
LLNotificationsUtil::add("ClickBuildConstants");
}
std::string shortfloat(F32 in)
{
std::string out = llformat("%f", in);
int i = out.size();
while(out[--i] == '0') out.erase(i, 1);
return out;
}
void LLPanelObject::onCopyPos(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLVector3 newpos(self->mCtrlPosX->get(), self->mCtrlPosY->get(), self->mCtrlPosZ->get());
self->mClipboardPos = newpos;
std::string stringVec = "<";
stringVec.append(shortfloat(newpos.mV[VX]));
stringVec.append(", ");
stringVec.append(shortfloat(newpos.mV[VY]));
stringVec.append(", ");
stringVec.append(shortfloat(newpos.mV[VZ]));
stringVec.append(">");
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
}
void LLPanelObject::onCopySize(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLVector3 newpos(self->mCtrlScaleX->get(), self->mCtrlScaleY->get(), self->mCtrlScaleZ->get());
self->mClipboardSize = newpos;
std::string stringVec = "<";
stringVec.append(shortfloat(newpos.mV[VX]));
stringVec.append(", ");
stringVec.append(shortfloat(newpos.mV[VY]));
stringVec.append(", ");
stringVec.append(shortfloat(newpos.mV[VZ]));
stringVec.append(">");
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
}
void LLPanelObject::onCopyRot(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLVector3 newpos(self->mCtrlRotX->get(), self->mCtrlRotY->get(), self->mCtrlRotZ->get());
self->mClipboardRot = newpos;
std::string stringVec = "<";
stringVec.append(shortfloat(newpos.mV[VX]));
stringVec.append(", ");
stringVec.append(shortfloat(newpos.mV[VY]));
stringVec.append(", ");
stringVec.append(shortfloat(newpos.mV[VZ]));
stringVec.append(">");
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec));
}
namespace
{
bool texturePermsCheck(const LLUUID& id)
{
return (id.notNull() && !gInventory.isObjectDescendentOf(id, gInventory.getLibraryRootFolderID())
&& id != LLUUID(gSavedSettings.getString("DefaultObjectTexture"))
&& id != LLUUID(gSavedSettings.getString("UIImgWhiteUUID"))
&& id != LLUUID(gSavedSettings.getString("UIImgInvisibleUUID"))
&& id != LLUUID(std::string("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903")) // alpha
&& LLPanelObject::findItemID(id).isNull());
}
}
void LLPanelObject::onCopyParams(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
if (!self) return;
self->getVolumeParams(mClipboardVolumeParams);
hasParamClipboard = TRUE;
LLViewerObject* objp = self->mObject;
mClipboardFlexiParams = objp->getFlexibleObjectData();
mClipboardLightParams = objp->getLightParams();
mClipboardSculptParams = objp->getSculptParams();
if (mClipboardSculptParams)
{
const LLUUID id = mClipboardSculptParams->getSculptTexture();
if (id != LLUUID(SCULPT_DEFAULT_TEXTURE) && !texturePermsCheck(id))
mClipboardSculptParams = NULL;
}
mClipboardLightImageParams = objp->getLightImageParams();
if (mClipboardLightImageParams && texturePermsCheck(mClipboardLightImageParams->getLightTexture()))
{
mClipboardLightImageParams = NULL;
}
}
void LLPanelObject::onPasteParams(void* user_data)
{
if(!hasParamClipboard) return;
LLPanelObject* self = (LLPanelObject*) user_data;
if(!self) return;
LLViewerObject* objp = self->mObject;
if (mClipboardFlexiParams)
objp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, *mClipboardFlexiParams, true);
else
objp->setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, false, true);
if (mClipboardLightParams)
objp->setParameterEntry(LLNetworkData::PARAMS_LIGHT, *mClipboardLightParams, true);
else
objp->setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, false, true);
if (mClipboardSculptParams)
objp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, *mClipboardSculptParams, true);
else
objp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, false, true);
if (mClipboardLightImageParams)
objp->setParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE, *mClipboardLightImageParams, true);
else
objp->setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, false, true);
objp->updateVolume(mClipboardVolumeParams);
}
void LLPanelObject::onLinkObj(void* user_data)
{
LL_INFOS() << "Attempting link." << LL_ENDL;
LLSelectMgr::getInstance()->linkObjects();
}
void LLPanelObject::onUnlinkObj(void* user_data)
{
LL_INFOS() << "Attempting unlink." << LL_ENDL;
LLSelectMgr::getInstance()->unlinkObjects();
}
void LLPanelObject::onPastePos(void* user_data)
{
if(mClipboardPos.isNull()) return;
LLPanelObject* self = (LLPanelObject*) user_data;
LLCalc* calcp = LLCalc::getInstance();
float region_width = gAgent.getRegion()->getWidth();
mClipboardPos.mV[VX] = llclamp( mClipboardPos.mV[VX], -3.5f, region_width);
mClipboardPos.mV[VY] = llclamp( mClipboardPos.mV[VY], -3.5f, region_width);
mClipboardPos.mV[VZ] = llclamp( mClipboardPos.mV[VZ], -3.5f, gHippoLimits->getMaxHeight());
self->mCtrlPosX->set( mClipboardPos.mV[VX] );
self->mCtrlPosY->set( mClipboardPos.mV[VY] );
self->mCtrlPosZ->set( mClipboardPos.mV[VZ] );
calcp->setVar(LLCalc::X_POS, mClipboardPos.mV[VX]);
calcp->setVar(LLCalc::Y_POS, mClipboardPos.mV[VY]);
calcp->setVar(LLCalc::Z_POS, mClipboardPos.mV[VZ]);
self->sendPosition(FALSE);
}
void LLPanelObject::onPasteSize(void* user_data)
{
if(mClipboardSize.isNull()) return;
LLPanelObject* self = (LLPanelObject*) user_data;
LLCalc* calcp = LLCalc::getInstance();
mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale());
mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale());
mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale());
self->mCtrlScaleX->set( mClipboardSize.mV[VX] );
self->mCtrlScaleY->set( mClipboardSize.mV[VY] );
self->mCtrlScaleZ->set( mClipboardSize.mV[VZ] );
calcp->setVar(LLCalc::X_SCALE, mClipboardSize.mV[VX]);
calcp->setVar(LLCalc::Y_SCALE, mClipboardSize.mV[VY]);
calcp->setVar(LLCalc::Z_SCALE, mClipboardSize.mV[VZ]);
self->sendScale(FALSE);
}
void LLPanelObject::onPasteRot(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLCalc* calcp = LLCalc::getInstance();
self->mCtrlRotX->set( mClipboardRot.mV[VX] );
self->mCtrlRotY->set( mClipboardRot.mV[VY] );
self->mCtrlRotZ->set( mClipboardRot.mV[VZ] );
calcp->setVar(LLCalc::X_ROT, mClipboardRot.mV[VX]);
calcp->setVar(LLCalc::Y_ROT, mClipboardRot.mV[VY]);
calcp->setVar(LLCalc::Z_ROT, mClipboardRot.mV[VZ]);
self->sendRotation(FALSE);
}
BOOL getvectorfromclip(const std::string& buf, LLVector3* value)
{
if( buf.empty() || value == NULL)
{
return FALSE;
}
LLVector3 v;
S32 count = sscanf( buf.c_str(), "<%f, %f, %f>", v.mV + 0, v.mV + 1, v.mV + 2 );
if( 3 == count )
{
value->setVec( v );
return TRUE;
}
return FALSE;
}
void LLPanelObject::onPastePosClip(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLCalc* calcp = LLCalc::getInstance();
LLWString temp_string;
LLView::getWindow()->pasteTextFromClipboard(temp_string);
std::string stringVec = wstring_to_utf8str(temp_string);
if(!getvectorfromclip(stringVec, &mClipboardPos)) return;
const LLViewerRegion* region(self->mObject ? self->mObject->getRegion() : NULL);
if (!region) return;
F32 region_width = region->getWidth();
mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], -3.5f, region_width);
mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], -3.5f, region_width);
mClipboardPos.mV[VZ] = llclamp(mClipboardPos.mV[VZ], -3.5f, gHippoLimits->getMaxHeight());
self->mCtrlPosX->set( mClipboardPos.mV[VX] );
self->mCtrlPosY->set( mClipboardPos.mV[VY] );
self->mCtrlPosZ->set( mClipboardPos.mV[VZ] );
calcp->setVar(LLCalc::X_POS, mClipboardPos.mV[VX]);
calcp->setVar(LLCalc::Y_POS, mClipboardPos.mV[VY]);
calcp->setVar(LLCalc::Z_POS, mClipboardPos.mV[VZ]);
self->sendPosition(FALSE);
}
void LLPanelObject::onPasteSizeClip(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLCalc* calcp = LLCalc::getInstance();
LLWString temp_string;
LLView::getWindow()->pasteTextFromClipboard(temp_string);
std::string stringVec = wstring_to_utf8str(temp_string);
if(!getvectorfromclip(stringVec, &mClipboardSize)) return;
mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale());
mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale());
mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale());
self->mCtrlScaleX->set( mClipboardSize.mV[VX] );
self->mCtrlScaleY->set( mClipboardSize.mV[VY] );
self->mCtrlScaleZ->set( mClipboardSize.mV[VZ] );
calcp->setVar(LLCalc::X_SCALE, mClipboardSize.mV[VX]);
calcp->setVar(LLCalc::Y_SCALE, mClipboardSize.mV[VY]);
calcp->setVar(LLCalc::Z_SCALE, mClipboardSize.mV[VZ]);
self->sendScale(FALSE);
}
void LLPanelObject::onPasteRotClip(void* user_data)
{
LLPanelObject* self = (LLPanelObject*) user_data;
LLCalc* calcp = LLCalc::getInstance();
LLWString temp_string;
LLView::getWindow()->pasteTextFromClipboard(temp_string);
std::string stringVec = wstring_to_utf8str(temp_string);
if(!getvectorfromclip(stringVec, &mClipboardRot)) return;
self->mCtrlRotX->set( mClipboardRot.mV[VX] );
self->mCtrlRotY->set( mClipboardRot.mV[VY] );
self->mCtrlRotZ->set( mClipboardRot.mV[VZ] );
calcp->setVar(LLCalc::X_ROT, mClipboardRot.mV[VX]);
calcp->setVar(LLCalc::Y_ROT, mClipboardRot.mV[VY]);
calcp->setVar(LLCalc::Z_ROT, mClipboardRot.mV[VZ]);
self->sendRotation(FALSE);
}