diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llselectmgr.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llselectmgr.cpp')
-rw-r--r-- | indra/newview/llselectmgr.cpp | 17232 |
1 files changed, 8616 insertions, 8616 deletions
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 4a82bd175e..b7fc2ef123 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1,8616 +1,8616 @@ -/**
- * @file llselectmgr.cpp
- * @brief A manager for selected objects and faces.
- *
- * $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
-#define LLSELECTMGR_CPP
-#include "llselectmgr.h"
-#include "llmaterialmgr.h"
-
-// library includes
-#include "llcachename.h"
-#include "llavatarnamecache.h"
-#include "lldbstrings.h"
-#include "llgl.h"
-#include "llmediaentry.h"
-#include "llrender.h"
-#include "llnotifications.h"
-#include "llpermissions.h"
-#include "llpermissionsflags.h"
-#include "lltrans.h"
-#include "llundo.h"
-#include "lluuid.h"
-#include "llvolume.h"
-#include "llcontrolavatar.h"
-#include "message.h"
-#include "object_flags.h"
-#include "llquaternion.h"
-
-// viewer includes
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llattachmentsmgr.h"
-#include "llviewerwindow.h"
-#include "lldrawable.h"
-#include "llfloaterinspect.h"
-#include "llfloaterreporter.h"
-#include "llfloaterreg.h"
-#include "llfloatertools.h"
-#include "llframetimer.h"
-#include "llfocusmgr.h"
-#include "llgltfmateriallist.h"
-#include "llhudeffecttrail.h"
-#include "llhudmanager.h"
-#include "llinventorymodel.h"
-#include "llmenugl.h"
-#include "llmeshrepository.h"
-#include "llmutelist.h"
-#include "llnotificationsutil.h"
-#include "llsidepaneltaskinfo.h"
-#include "llslurl.h"
-#include "llstatusbar.h"
-#include "llsurface.h"
-#include "lltool.h"
-#include "lltooldraganddrop.h"
-#include "lltoolmgr.h"
-#include "lltoolpie.h"
-#include "llui.h"
-#include "llviewercamera.h"
-#include "llviewercontrol.h"
-#include "llviewertexturelist.h"
-#include "llviewermedia.h"
-#include "llviewermediafocus.h"
-#include "llviewermenu.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llvoavatarself.h"
-#include "llvovolume.h"
-#include "pipeline.h"
-#include "llviewershadermgr.h"
-#include "llpanelface.h"
-#include "llglheaders.h"
-#include "llinventoryobserver.h"
-
-LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
-//
-// Consts
-//
-
-const F32 SILHOUETTE_UPDATE_THRESHOLD_SQUARED = 0.02f;
-const S32 MAX_SILS_PER_FRAME = 50;
-const S32 MAX_OBJECTS_PER_PACKET = 254;
-// For linked sets
-const S32 MAX_CHILDREN_PER_TASK = 255;
-
-//
-// Globals
-//
-
-//bool gDebugSelectMgr = false;
-
-//bool gHideSelectedObjects = false;
-//bool gAllowSelectAvatar = false;
-
-bool LLSelectMgr::sRectSelectInclusive = true;
-bool LLSelectMgr::sRenderHiddenSelections = true;
-bool LLSelectMgr::sRenderLightRadius = false;
-F32 LLSelectMgr::sHighlightThickness = 0.f;
-F32 LLSelectMgr::sHighlightUScale = 0.f;
-F32 LLSelectMgr::sHighlightVScale = 0.f;
-F32 LLSelectMgr::sHighlightAlpha = 0.f;
-F32 LLSelectMgr::sHighlightAlphaTest = 0.f;
-F32 LLSelectMgr::sHighlightUAnim = 0.f;
-F32 LLSelectMgr::sHighlightVAnim = 0.f;
-LLColor4 LLSelectMgr::sSilhouetteParentColor;
-LLColor4 LLSelectMgr::sSilhouetteChildColor;
-LLColor4 LLSelectMgr::sHighlightInspectColor;
-LLColor4 LLSelectMgr::sHighlightParentColor;
-LLColor4 LLSelectMgr::sHighlightChildColor;
-LLColor4 LLSelectMgr::sContextSilhouetteColor;
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// struct LLDeRezInfo
-//
-// Used to keep track of important derez info.
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-struct LLDeRezInfo
-{
- EDeRezDestination mDestination;
- LLUUID mDestinationID;
- LLDeRezInfo(EDeRezDestination dest, const LLUUID& dest_id) :
- mDestination(dest), mDestinationID(dest_id) {}
-};
-
-//
-// Imports
-//
-
-//-----------------------------------------------------------------------------
-// ~LLSelectionCallbackData()
-//-----------------------------------------------------------------------------
-
-LLSelectionCallbackData::LLSelectionCallbackData()
-{
- LLSelectMgr *instance = LLSelectMgr::getInstance();
- LLObjectSelectionHandle selection = instance->getSelection();
- if (!selection->getNumNodes())
- {
- return;
- }
- mSelectedObjects = new LLObjectSelection();
-
- for (LLObjectSelection::iterator iter = selection->begin();
- iter != selection->end();)
- {
- LLObjectSelection::iterator curiter = iter++;
-
- LLSelectNode *nodep = *curiter;
- LLViewerObject* objectp = nodep->getObject();
-
- if (!objectp)
- {
- mSelectedObjects->mSelectType = SELECT_TYPE_WORLD;
- }
- else
- {
- LLSelectNode* new_nodep = new LLSelectNode(*nodep);
- mSelectedObjects->addNode(new_nodep);
-
- if (objectp->isHUDAttachment())
- {
- mSelectedObjects->mSelectType = SELECT_TYPE_HUD;
- }
- else if (objectp->isAttachment())
- {
- mSelectedObjects->mSelectType = SELECT_TYPE_ATTACHMENT;
- }
- else
- {
- mSelectedObjects->mSelectType = SELECT_TYPE_WORLD;
- }
- }
- }
-}
-
-
-//
-// Functions
-//
-
-void LLSelectMgr::cleanupGlobals()
-{
- LLSelectMgr::getInstance()->clearSelections();
-}
-
-//-----------------------------------------------------------------------------
-// LLSelectMgr()
-//-----------------------------------------------------------------------------
-LLSelectMgr::LLSelectMgr()
- : mHideSelectedObjects(LLCachedControl<bool>(gSavedSettings, "HideSelectedObjects", false)),
- mRenderHighlightSelections(LLCachedControl<bool>(gSavedSettings, "RenderHighlightSelections", true)),
- mAllowSelectAvatar( LLCachedControl<bool>(gSavedSettings, "AllowSelectAvatar", false)),
- mDebugSelectMgr(LLCachedControl<bool>(gSavedSettings, "DebugSelectMgr", false))
-{
- mTEMode = false;
- mTextureChannel = LLRender::DIFFUSE_MAP;
- mLastCameraPos.clearVec();
-
- sHighlightThickness = gSavedSettings.getF32("SelectionHighlightThickness");
- sHighlightUScale = gSavedSettings.getF32("SelectionHighlightUScale");
- sHighlightVScale = gSavedSettings.getF32("SelectionHighlightVScale");
- sHighlightAlpha = gSavedSettings.getF32("SelectionHighlightAlpha") * 2;
- sHighlightAlphaTest = gSavedSettings.getF32("SelectionHighlightAlphaTest");
- sHighlightUAnim = gSavedSettings.getF32("SelectionHighlightUAnim");
- sHighlightVAnim = gSavedSettings.getF32("SelectionHighlightVAnim");
-
- sSilhouetteParentColor =LLUIColorTable::instance().getColor("SilhouetteParentColor");
- sSilhouetteChildColor = LLUIColorTable::instance().getColor("SilhouetteChildColor");
- sHighlightParentColor = LLUIColorTable::instance().getColor("HighlightParentColor");
- sHighlightChildColor = LLUIColorTable::instance().getColor("HighlightChildColor");
- sHighlightInspectColor = LLUIColorTable::instance().getColor("HighlightInspectColor");
- sContextSilhouetteColor = LLUIColorTable::instance().getColor("ContextSilhouetteColor")*0.5f;
-
- sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
-
- mRenderSilhouettes = true;
-
- mGridMode = GRID_MODE_WORLD;
- gSavedSettings.setS32("GridMode", (S32)GRID_MODE_WORLD);
-
- mSelectedObjects = new LLObjectSelection();
- mHoverObjects = new LLObjectSelection();
- mHighlightedObjects = new LLObjectSelection();
-
- mForceSelection = false;
- mShowSelection = false;
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLSelectMgr()
-//-----------------------------------------------------------------------------
-LLSelectMgr::~LLSelectMgr()
-{
- clearSelections();
-}
-
-void LLSelectMgr::clearSelections()
-{
- mHoverObjects->deleteAllNodes();
- mSelectedObjects->deleteAllNodes();
- mHighlightedObjects->deleteAllNodes();
- mRectSelectedObjects.clear();
- mGridObjects.deleteAllNodes();
-
- LLPipeline::setRenderHighlightTextureChannel(LLRender::DIFFUSE_MAP);
-}
-
-void LLSelectMgr::update()
-{
- mSelectedObjects->cleanupNodes();
-}
-
-void LLSelectMgr::updateEffects()
-{
- //keep reference grid objects active
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- LLDrawable* drawable = object->mDrawable;
- if (drawable)
- {
- gPipeline.markMoved(drawable);
- }
- return true;
- }
- } func;
- mGridObjects.applyToObjects(&func);
-
- if (mEffectsTimer.getElapsedTimeF32() > 1.f)
- {
- mSelectedObjects->updateEffects();
- mEffectsTimer.reset();
- }
-}
-
-void LLSelectMgr::resetObjectOverrides()
-{
- resetObjectOverrides(getSelection());
-}
-
-void LLSelectMgr::resetObjectOverrides(LLObjectSelectionHandle selected_handle)
-{
- struct f : public LLSelectedNodeFunctor
- {
- f(bool a, LLSelectMgr* p) : mAvatarOverridesPersist(a), mManager(p) {}
- bool mAvatarOverridesPersist;
- LLSelectMgr* mManager;
- virtual bool apply(LLSelectNode* node)
- {
- if (mAvatarOverridesPersist)
- {
- LLViewerObject* object = node->getObject();
- if (object && !object->getParent())
- {
- LLVOAvatar* avatar = object->asAvatar();
- if (avatar)
- {
- mManager->mAvatarOverridesMap.emplace(avatar->getID(), AvatarPositionOverride(node->mLastPositionLocal, node->mLastRotation, object));
- }
- }
- }
- node->mLastPositionLocal.setVec(0, 0, 0);
- node->mLastRotation = LLQuaternion();
- node->mLastScale.setVec(0, 0, 0);
- return true;
- }
- } func(mAllowSelectAvatar, this);
-
- selected_handle->applyToNodes(&func);
-}
-
-void LLSelectMgr::overrideObjectUpdates()
-{
- //override any position updates from simulator on objects being edited
- struct f : public LLSelectedNodeFunctor
- {
- virtual bool apply(LLSelectNode* selectNode)
- {
- LLViewerObject* object = selectNode->getObject();
- if (object && object->permMove() && !object->isPermanentEnforced())
- {
- if (!selectNode->mLastPositionLocal.isExactlyZero())
- {
- object->setPosition(selectNode->mLastPositionLocal);
- }
- if (selectNode->mLastRotation != LLQuaternion())
- {
- object->setRotation(selectNode->mLastRotation);
- }
- if (!selectNode->mLastScale.isExactlyZero())
- {
- object->setScale(selectNode->mLastScale);
- }
- }
- return true;
- }
- } func;
- getSelection()->applyToNodes(&func);
-}
-
-void LLSelectMgr::resetAvatarOverrides()
-{
- mAvatarOverridesMap.clear();
-}
-
-void LLSelectMgr::overrideAvatarUpdates()
-{
- if (mAvatarOverridesMap.size() == 0)
- {
- return;
- }
-
- if (!mAllowSelectAvatar || !gFloaterTools)
- {
- resetAvatarOverrides();
- return;
- }
-
- if (!gFloaterTools->getVisible() && getSelection()->isEmpty())
- {
- // when user switches selection, floater is invisible and selection is empty
- LLToolset *toolset = LLToolMgr::getInstance()->getCurrentToolset();
- if (toolset->isShowFloaterTools()
- && toolset->isToolSelected(0)) // Pie tool
- {
- resetAvatarOverrides();
- return;
- }
- }
-
- // remove selected avatars from this list,
- // but set object overrides to make sure avatar won't snap back
- struct f : public LLSelectedNodeFunctor
- {
- f(LLSelectMgr* p) : mManager(p) {}
- LLSelectMgr* mManager;
- virtual bool apply(LLSelectNode* selectNode)
- {
- LLViewerObject* object = selectNode->getObject();
- if (object && !object->getParent())
- {
- LLVOAvatar* avatar = object->asAvatar();
- if (avatar)
- {
- uuid_av_override_map_t::iterator iter = mManager->mAvatarOverridesMap.find(avatar->getID());
- if (iter != mManager->mAvatarOverridesMap.end())
- {
- if (selectNode->mLastPositionLocal.isExactlyZero())
- {
- selectNode->mLastPositionLocal = iter->second.mLastPositionLocal;
- }
- if (selectNode->mLastRotation == LLQuaternion())
- {
- selectNode->mLastRotation = iter->second.mLastRotation;
- }
- mManager->mAvatarOverridesMap.erase(iter);
- }
- }
- }
- return true;
- }
- } func(this);
- getSelection()->applyToNodes(&func);
-
- // Override avatar positions
- uuid_av_override_map_t::iterator it = mAvatarOverridesMap.begin();
- while (it != mAvatarOverridesMap.end())
- {
- if (it->second.mObject->isDead())
- {
- it = mAvatarOverridesMap.erase(it);
- }
- else
- {
- if (!it->second.mLastPositionLocal.isExactlyZero())
- {
- it->second.mObject->setPosition(it->second.mLastPositionLocal);
- }
- if (it->second.mLastRotation != LLQuaternion())
- {
- it->second.mObject->setRotation(it->second.mLastRotation);
- }
- it++;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Select just the object, not any other group members.
-//-----------------------------------------------------------------------------
-LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face)
-{
- llassert( object );
-
- //remember primary object
- mSelectedObjects->mPrimaryObject = object;
-
- // Don't add an object that is already in the list
- if (object->isSelected() ) {
- // make sure point at position is updated
- updatePointAt();
- gEditMenuHandler = this;
- return NULL;
- }
-
- if (!canSelectObject(object))
- {
- //make_ui_sound("UISndInvalidOp");
- return NULL;
- }
-
- // LL_INFOS() << "Adding object to selected object list" << LL_ENDL;
-
- // Place it in the list and tag it.
- // This will refresh dialogs.
- addAsIndividual(object, face);
-
- // Stop the object from moving (this anticipates changes on the
- // simulator in LLTask::userSelect)
- // *FIX: shouldn't zero out these either
- object->setVelocity(LLVector3::zero);
- object->setAcceleration(LLVector3::zero);
- //object->setAngularVelocity(LLVector3::zero);
- object->resetRot();
-
- // Always send to simulator, so you get a copy of the
- // permissions structure back.
- gMessageSystem->newMessageFast(_PREHASH_ObjectSelect);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
- LLViewerRegion* regionp = object->getRegion();
- gMessageSystem->sendReliable( regionp->getHost());
-
- updatePointAt();
- updateSelectionCenter();
- saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
-
- // have selection manager handle edit menu immediately after
- // user selects an object
- if (mSelectedObjects->getObjectCount())
- {
- gEditMenuHandler = this;
- }
-
- return mSelectedObjects;
-}
-
-//-----------------------------------------------------------------------------
-// Select the object, parents and children.
-//-----------------------------------------------------------------------------
-LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, bool add_to_end, bool ignore_select_owned)
-{
- llassert( obj );
-
- //remember primary object
- mSelectedObjects->mPrimaryObject = obj;
-
- // This may be incorrect if things weren't family selected before... - djs 07/08/02
- // Don't add an object that is already in the list
- if (obj->isSelected() )
- {
- // make sure pointat position is updated
- updatePointAt();
- gEditMenuHandler = this;
- return NULL;
- }
-
- if (!canSelectObject(obj,ignore_select_owned))
- {
- //make_ui_sound("UISndInvalidOp");
- return NULL;
- }
-
- // Since we're selecting a family, start at the root, but
- // don't include an avatar.
- LLViewerObject* root = obj;
-
- while(!root->isAvatar() && root->getParent())
- {
- LLViewerObject* parent = (LLViewerObject*)root->getParent();
- if (parent->isAvatar())
- {
- break;
- }
- root = parent;
- }
-
- // Collect all of the objects
- std::vector<LLViewerObject*> objects;
-
- root->addThisAndNonJointChildren(objects);
- addAsFamily(objects, add_to_end);
-
- updateSelectionCenter();
- saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
- updatePointAt();
-
- dialog_refresh_all();
-
- // Always send to simulator, so you get a copy of the permissions
- // structure back.
- sendSelect();
-
- // Stop the object from moving (this anticipates changes on the
- // simulator in LLTask::userSelect)
- root->setVelocity(LLVector3::zero);
- root->setAcceleration(LLVector3::zero);
- //root->setAngularVelocity(LLVector3::zero);
- root->resetRot();
-
- // leave component mode
- if (gSavedSettings.getBOOL("EditLinkedParts"))
- {
- gSavedSettings.setBOOL("EditLinkedParts", false);
- promoteSelectionToRoot();
- }
-
- // have selection manager handle edit menu immediately after
- // user selects an object
- if (mSelectedObjects->getObjectCount())
- {
- gEditMenuHandler = this;
- }
-
- return mSelectedObjects;
-}
-
-//-----------------------------------------------------------------------------
-// Select the object, parents and children.
-//-----------------------------------------------------------------------------
-LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list,
- bool send_to_sim)
-{
- // Collect all of the objects, children included
- std::vector<LLViewerObject*> objects;
-
- //clear primary object (no primary object)
- mSelectedObjects->mPrimaryObject = NULL;
-
- if (object_list.size() < 1)
- {
- return NULL;
- }
-
- // NOTE -- we add the objects in REVERSE ORDER
- // to preserve the order in the mSelectedObjects list
- for (std::vector<LLViewerObject*>::const_reverse_iterator riter = object_list.rbegin();
- riter != object_list.rend(); ++riter)
- {
- LLViewerObject *object = *riter;
-
- llassert( object );
-
- if (!canSelectObject(object)) continue;
-
- object->addThisAndNonJointChildren(objects);
- addAsFamily(objects);
-
- // Stop the object from moving (this anticipates changes on the
- // simulator in LLTask::userSelect)
- object->setVelocity(LLVector3::zero);
- object->setAcceleration(LLVector3::zero);
- //object->setAngularVelocity(LLVector3::zero);
- object->resetRot();
- }
-
- updateSelectionCenter();
- saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
- updatePointAt();
- dialog_refresh_all();
-
- // Almost always send to simulator, so you get a copy of the permissions
- // structure back.
- // JC: The one case where you don't want to do this is if you're selecting
- // all the objects on a sim.
- if (send_to_sim)
- {
- sendSelect();
- }
-
- // leave component mode
- if (gSavedSettings.getBOOL("EditLinkedParts"))
- {
- gSavedSettings.setBOOL("EditLinkedParts", false);
- promoteSelectionToRoot();
- }
-
- // have selection manager handle edit menu immediately after
- // user selects an object
- if (mSelectedObjects->getObjectCount())
- {
- gEditMenuHandler = this;
- }
-
- return mSelectedObjects;
-}
-
-// Use for when the simulator kills an object. This version also
-// handles informing the current tool of the object's deletion.
-//
-// Caller needs to call dialog_refresh_all if necessary.
-bool LLSelectMgr::removeObjectFromSelections(const LLUUID &id)
-{
- bool object_found = false;
- LLTool *tool = NULL;
-
- tool = LLToolMgr::getInstance()->getCurrentTool();
-
- // It's possible that the tool is editing an object that is not selected
- LLViewerObject* tool_editing_object = tool->getEditingObject();
- if( tool_editing_object && tool_editing_object->mID == id)
- {
- tool->stopEditing();
- object_found = true;
- }
-
- // Iterate through selected objects list and kill the object
- if( !object_found )
- {
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); )
- {
- LLObjectSelection::iterator curiter = iter++;
- LLViewerObject* object = (*curiter)->getObject();
- if (object->mID == id)
- {
- if (tool)
- {
- tool->stopEditing();
- }
-
- // lose the selection, don't tell simulator, it knows
- deselectObjectAndFamily(object, false);
- object_found = true;
- break; // must break here, may have removed multiple objects from list
- }
- else if (object->isAvatar() && object->getParent() && ((LLViewerObject*)object->getParent())->mID == id)
- {
- // It's possible the item being removed has an avatar sitting on it
- // So remove the avatar that is sitting on the object.
- deselectObjectAndFamily(object, false);
- break; // must break here, may have removed multiple objects from list
- }
- }
- }
-
- return object_found;
-}
-
-bool LLSelectMgr::linkObjects()
-{
- if (!LLSelectMgr::getInstance()->selectGetAllRootsValid())
- {
- LLNotificationsUtil::add("UnableToLinkWhileDownloading");
- return true;
- }
-
- S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
- if (object_count > MAX_CHILDREN_PER_TASK + 1)
- {
- LLSD args;
- args["COUNT"] = llformat("%d", object_count);
- int max = MAX_CHILDREN_PER_TASK+1;
- args["MAX"] = llformat("%d", max);
- LLNotificationsUtil::add("UnableToLinkObjects", args);
- return true;
- }
-
- if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2)
- {
- LLNotificationsUtil::add("CannotLinkIncompleteSet");
- return true;
- }
-
- if (!LLSelectMgr::getInstance()->selectGetRootsModify())
- {
- LLNotificationsUtil::add("CannotLinkModify");
- return true;
- }
-
- if (!LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced())
- {
- LLNotificationsUtil::add("CannotLinkPermanent");
- return true;
- }
-
- LLUUID owner_id;
- std::string owner_name;
- if (!LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name))
- {
- // we don't actually care if you're the owner, but novices are
- // the most likely to be stumped by this one, so offer the
- // easiest and most likely solution.
- LLNotificationsUtil::add("CannotLinkDifferentOwners");
- return true;
- }
-
- if (!LLSelectMgr::getInstance()->selectGetSameRegion())
- {
- LLNotificationsUtil::add("CannotLinkAcrossRegions");
- return true;
- }
-
- LLSelectMgr::getInstance()->sendLink();
-
- return true;
-}
-
-bool LLSelectMgr::unlinkObjects()
-{
- S32 min_objects_for_confirm = gSavedSettings.getS32("MinObjectsForUnlinkConfirm");
- S32 unlink_object_count = mSelectedObjects->getObjectCount(); // clears out nodes with NULL objects
- if (unlink_object_count >= min_objects_for_confirm
- && unlink_object_count > mSelectedObjects->getRootObjectCount())
- {
- // total count > root count means that there are childer inside and that there are linksets that will be unlinked
- LLNotificationsUtil::add("ConfirmUnlink", LLSD(), LLSD(), boost::bind(&LLSelectMgr::confirmUnlinkObjects, this, _1, _2));
- return true;
- }
-
- LLSelectMgr::getInstance()->sendDelink();
- return true;
-}
-
-void LLSelectMgr::confirmUnlinkObjects(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- // if Cancel pressed
- if (option == 1)
- {
- return;
- }
-
- LLSelectMgr::getInstance()->sendDelink();
- return;
-}
-
-// in order to link, all objects must have the same owner, and the
-// agent must have the ability to modify all of the objects. However,
-// we're not answering that question with this method. The question
-// we're answering is: does the user have a reasonable expectation
-// that a link operation should work? If so, return true, false
-// otherwise. this allows the handle_link method to more finely check
-// the selection and give an error message when the uer has a
-// reasonable expectation for the link to work, but it will fail.
-//
-// For animated objects, there's additional check that if the
-// selection includes at least one animated object, the total mesh
-// triangle count cannot exceed the designated limit.
-bool LLSelectMgr::enableLinkObjects()
-{
- bool new_value = false;
- // check if there are at least 2 objects selected, and that the
- // user can modify at least one of the selected objects.
-
- // in component mode, can't link
- if (!gSavedSettings.getBOOL("EditLinkedParts"))
- {
- if(LLSelectMgr::getInstance()->selectGetAllRootsValid() && LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() >= 2)
- {
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- LLViewerObject *root_object = (object == NULL) ? NULL : object->getRootEdit();
- return object->permModify() && !object->isPermanentEnforced() &&
- ((root_object == NULL) || !root_object->isPermanentEnforced());
- }
- } func;
- const bool firstonly = true;
- new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
- }
- }
- if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable())
- {
- new_value = false;
- }
- return new_value;
-}
-
-bool LLSelectMgr::enableUnlinkObjects()
-{
- LLViewerObject* first_editable_object = LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject();
- LLViewerObject *root_object = (first_editable_object == NULL) ? NULL : first_editable_object->getRootEdit();
-
- bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() &&
- first_editable_object &&
- !first_editable_object->isAttachment() && !first_editable_object->isPermanentEnforced() &&
- ((root_object == NULL) || !root_object->isPermanentEnforced());
-
- return new_value;
-}
-
-void LLSelectMgr::deselectObjectAndFamily(LLViewerObject* object, bool send_to_sim, bool include_entire_object)
-{
- // bail if nothing selected or if object wasn't selected in the first place
- if(!object) return;
- if(!object->isSelected()) return;
-
- // Collect all of the objects, and remove them
- std::vector<LLViewerObject*> objects;
-
- if (include_entire_object)
- {
- // Since we're selecting a family, start at the root, but
- // don't include an avatar.
- LLViewerObject* root = object;
-
- while(!root->isAvatar() && root->getParent())
- {
- LLViewerObject* parent = (LLViewerObject*)root->getParent();
- if (parent->isAvatar())
- {
- break;
- }
- root = parent;
- }
-
- object = root;
- }
- else
- {
- object = (LLViewerObject*)object->getRoot();
- }
-
- object->addThisAndAllChildren(objects);
- remove(objects);
-
- if (!send_to_sim) return;
-
- //-----------------------------------------------------------
- // Inform simulator of deselection
- //-----------------------------------------------------------
- LLViewerRegion* regionp = object->getRegion();
-
- bool start_new_message = true;
- S32 select_count = 0;
-
- LLMessageSystem* msg = gMessageSystem;
- for (U32 i = 0; i < objects.size(); i++)
- {
- if (start_new_message)
- {
- msg->newMessageFast(_PREHASH_ObjectDeselect);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- select_count++;
- start_new_message = false;
- }
-
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, (objects[i])->getLocalID());
- select_count++;
-
- // Zap the angular velocity, as the sim will set it to zero
- objects[i]->setAngularVelocity( 0,0,0 );
- objects[i]->setVelocity( 0,0,0 );
-
- if(msg->isSendFull(NULL) || select_count >= MAX_OBJECTS_PER_PACKET)
- {
- msg->sendReliable(regionp->getHost() );
- select_count = 0;
- start_new_message = true;
- }
- }
-
- if (!start_new_message)
- {
- msg->sendReliable(regionp->getHost() );
- }
-
- updatePointAt();
- updateSelectionCenter();
-}
-
-void LLSelectMgr::deselectObjectOnly(LLViewerObject* object, bool send_to_sim)
-{
- // bail if nothing selected or if object wasn't selected in the first place
- if (!object) return;
- if (!object->isSelected() ) return;
-
- // Zap the angular velocity, as the sim will set it to zero
- object->setAngularVelocity( 0,0,0 );
- object->setVelocity( 0,0,0 );
-
- if (send_to_sim)
- {
- LLViewerRegion* region = object->getRegion();
- gMessageSystem->newMessageFast(_PREHASH_ObjectDeselect);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
- gMessageSystem->sendReliable(region->getHost());
- }
-
- // This will refresh dialogs.
- remove( object );
-
- updatePointAt();
- updateSelectionCenter();
-}
-
-
-//-----------------------------------------------------------------------------
-// addAsFamily
-//-----------------------------------------------------------------------------
-
-void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, bool add_to_end)
-{
- for (std::vector<LLViewerObject*>::iterator iter = objects.begin();
- iter != objects.end(); ++iter)
- {
- LLViewerObject* objectp = *iter;
-
- // Can't select yourself
- if (objectp->mID == gAgentID
- && !mAllowSelectAvatar)
- {
- continue;
- }
-
- if (!objectp->isSelected())
- {
- LLSelectNode *nodep = new LLSelectNode(objectp, true);
- if (add_to_end)
- {
- mSelectedObjects->addNodeAtEnd(nodep);
- }
- else
- {
- mSelectedObjects->addNode(nodep);
- }
- objectp->setSelected(true);
-
- if (objectp->getNumTEs() > 0)
- {
- nodep->selectAllTEs(true);
- objectp->setAllTESelected(true);
- }
- else
- {
- // object has no faces, so don't mess with faces
- }
- }
- else
- {
- // we want this object to be selected for real
- // so clear transient flag
- LLSelectNode* select_node = mSelectedObjects->findNode(objectp);
- if (select_node)
- {
- select_node->setTransient(false);
- }
- }
- }
- saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
-}
-
-//-----------------------------------------------------------------------------
-// addAsIndividual() - a single object, face, etc
-//-----------------------------------------------------------------------------
-void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, bool undoable)
-{
- // check to see if object is already in list
- LLSelectNode *nodep = mSelectedObjects->findNode(objectp);
-
- // if not in list, add it
- if (!nodep)
- {
- nodep = new LLSelectNode(objectp, true);
- mSelectedObjects->addNode(nodep);
- llassert_always(nodep->getObject());
- }
- else
- {
- // make this a full-fledged selection
- nodep->setTransient(false);
- // Move it to the front of the list
- mSelectedObjects->moveNodeToFront(nodep);
- }
-
- // Make sure the object is tagged as selected
- objectp->setSelected( true );
-
- // And make sure we don't consider it as part of a family
- nodep->mIndividualSelection = true;
-
- // Handle face selection
- if (objectp->getNumTEs() <= 0)
- {
- // object has no faces, so don't do anything
- }
- else if (face == SELECT_ALL_TES)
- {
- nodep->selectAllTEs(true);
- objectp->setAllTESelected(true);
- }
- else if (0 <= face && face < SELECT_MAX_TES)
- {
- nodep->selectTE(face, true);
- objectp->setTESelected(face, true);
- }
- else
- {
- LL_ERRS() << "LLSelectMgr::add face " << face << " out-of-range" << LL_ENDL;
- return;
- }
-
- saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
- updateSelectionCenter();
- dialog_refresh_all();
-}
-
-
-LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32 face)
-{
- if (!objectp)
- {
- mHoverObjects->deleteAllNodes();
- return NULL;
- }
-
- // Can't select yourself
- if (objectp->mID == gAgentID)
- {
- mHoverObjects->deleteAllNodes();
- return NULL;
- }
-
- // Can't select land
- if (objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
- {
- mHoverObjects->deleteAllNodes();
- return NULL;
- }
-
- mHoverObjects->mPrimaryObject = objectp;
-
- objectp = objectp->getRootEdit();
-
- // is the requested object the same as the existing hover object root?
- // NOTE: there is only ever one linked set in mHoverObjects
- if (mHoverObjects->getFirstRootObject() != objectp)
- {
-
- // Collect all of the objects
- std::vector<LLViewerObject*> objects;
- objectp = objectp->getRootEdit();
- objectp->addThisAndNonJointChildren(objects);
-
- mHoverObjects->deleteAllNodes();
- for (std::vector<LLViewerObject*>::iterator iter = objects.begin();
- iter != objects.end(); ++iter)
- {
- LLViewerObject* cur_objectp = *iter;
- if(!cur_objectp || cur_objectp->isDead())
- {
- continue;
- }
- LLSelectNode* nodep = new LLSelectNode(cur_objectp, false);
- nodep->selectTE(face, true);
- mHoverObjects->addNodeAtEnd(nodep);
- }
-
- requestObjectPropertiesFamily(objectp);
- }
-
- return mHoverObjects;
-}
-
-LLSelectNode *LLSelectMgr::getHoverNode()
-{
- return mHoverObjects->getFirstRootNode();
-}
-
-LLSelectNode *LLSelectMgr::getPrimaryHoverNode()
-{
- return mHoverObjects->mSelectNodeMap[mHoverObjects->mPrimaryObject];
-}
-
-void LLSelectMgr::highlightObjectOnly(LLViewerObject* objectp)
-{
- if (!objectp)
- {
- return;
- }
-
- if (objectp->getPCode() != LL_PCODE_VOLUME)
- {
- return;
- }
-
- if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner())
- || (gSavedSettings.getBOOL("SelectMovableOnly") && (!objectp->permMove() || objectp->isPermanentEnforced())))
- {
- // only select my own objects
- return;
- }
-
- mRectSelectedObjects.insert(objectp);
-}
-
-void LLSelectMgr::highlightObjectAndFamily(LLViewerObject* objectp)
-{
- if (!objectp)
- {
- return;
- }
-
- LLViewerObject* root_obj = (LLViewerObject*)objectp->getRoot();
-
- highlightObjectOnly(root_obj);
-
- LLViewerObject::const_child_list_t& child_list = root_obj->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child = *iter;
- highlightObjectOnly(child);
- }
-}
-
-// Note that this ignores the "select owned only" flag
-// It's also more efficient than calling the single-object version over and over.
-void LLSelectMgr::highlightObjectAndFamily(const std::vector<LLViewerObject*>& objects)
-{
- for (std::vector<LLViewerObject*>::const_iterator iter1 = objects.begin();
- iter1 != objects.end(); ++iter1)
- {
- LLViewerObject* object = *iter1;
-
- if (!object)
- {
- continue;
- }
- if (object->getPCode() != LL_PCODE_VOLUME)
- {
- continue;
- }
-
- LLViewerObject* root = (LLViewerObject*)object->getRoot();
- mRectSelectedObjects.insert(root);
-
- LLViewerObject::const_child_list_t& child_list = root->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter2 = child_list.begin();
- iter2 != child_list.end(); iter2++)
- {
- LLViewerObject* child = *iter2;
- mRectSelectedObjects.insert(child);
- }
- }
-}
-
-void LLSelectMgr::unhighlightObjectOnly(LLViewerObject* objectp)
-{
- if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
- {
- return;
- }
-
- mRectSelectedObjects.erase(objectp);
-}
-
-void LLSelectMgr::unhighlightObjectAndFamily(LLViewerObject* objectp)
-{
- if (!objectp)
- {
- return;
- }
-
- LLViewerObject* root_obj = (LLViewerObject*)objectp->getRoot();
-
- unhighlightObjectOnly(root_obj);
-
- LLViewerObject::const_child_list_t& child_list = root_obj->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child = *iter;
- unhighlightObjectOnly(child);
- }
-}
-
-
-void LLSelectMgr::unhighlightAll()
-{
- mRectSelectedObjects.clear();
- mHighlightedObjects->deleteAllNodes();
-}
-
-LLObjectSelectionHandle LLSelectMgr::selectHighlightedObjects()
-{
- if (!mHighlightedObjects->getNumNodes())
- {
- return NULL;
- }
-
- //clear primary object
- mSelectedObjects->mPrimaryObject = NULL;
-
- for (LLObjectSelection::iterator iter = getHighlightedObjects()->begin();
- iter != getHighlightedObjects()->end(); )
- {
- LLObjectSelection::iterator curiter = iter++;
-
- LLSelectNode *nodep = *curiter;
- LLViewerObject* objectp = nodep->getObject();
-
- if (!canSelectObject(objectp))
- {
- continue;
- }
-
- // already selected
- if (objectp->isSelected())
- {
- continue;
- }
-
- LLSelectNode* new_nodep = new LLSelectNode(*nodep);
- mSelectedObjects->addNode(new_nodep);
-
- // flag this object as selected
- objectp->setSelected(true);
- objectp->setAllTESelected(true);
-
- mSelectedObjects->mSelectType = getSelectTypeForObject(objectp);
-
- // request properties on root objects
- if (objectp->isRootEdit())
- {
- requestObjectPropertiesFamily(objectp);
- }
- }
-
- // pack up messages to let sim know these objects are selected
- sendSelect();
- unhighlightAll();
- updateSelectionCenter();
- saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
- updatePointAt();
-
- if (mSelectedObjects->getObjectCount())
- {
- gEditMenuHandler = this;
- }
-
- return mSelectedObjects;
-}
-
-void LLSelectMgr::deselectHighlightedObjects()
-{
- bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
- for (std::set<LLPointer<LLViewerObject> >::iterator iter = mRectSelectedObjects.begin();
- iter != mRectSelectedObjects.end(); iter++)
- {
- LLViewerObject *objectp = *iter;
- if (!select_linked_set)
- {
- deselectObjectOnly(objectp);
- }
- else
- {
- LLViewerObject* root_object = (LLViewerObject*)objectp->getRoot();
- if (root_object->isSelected())
- {
- deselectObjectAndFamily(root_object);
- }
- }
- }
-
- unhighlightAll();
-}
-
-void LLSelectMgr::addGridObject(LLViewerObject* objectp)
-{
- LLSelectNode* nodep = new LLSelectNode(objectp, false);
- mGridObjects.addNodeAtEnd(nodep);
-
- LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child = *iter;
- nodep = new LLSelectNode(child, false);
- mGridObjects.addNodeAtEnd(nodep);
- }
-}
-
-void LLSelectMgr::clearGridObjects()
-{
- mGridObjects.deleteAllNodes();
-}
-
-void LLSelectMgr::setGridMode(EGridMode mode)
-{
- mGridMode = mode;
- gSavedSettings.setS32("GridMode", mode);
- updateSelectionCenter();
-}
-
-void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale, bool for_snap_guides)
-{
- mGridObjects.cleanupNodes();
-
- LLViewerObject* first_grid_object = mGridObjects.getFirstObject();
-
- if (mGridMode == GRID_MODE_LOCAL && mSelectedObjects->getObjectCount())
- {
- //LLViewerObject* root = getSelectedParentObject(mSelectedObjects->getFirstObject());
- mGridOrigin = mSavedSelectionBBox.getCenterAgent();
- mGridScale = mSavedSelectionBBox.getExtentLocal() * 0.5f;
-
- // DEV-12570 Just taking the saved selection box rotation prevents
- // wild rotations of linked sets while in local grid mode
- //if(mSelectedObjects->getObjectCount() < 2 || !root || root->mDrawable.isNull())
- {
- mGridRotation = mSavedSelectionBBox.getRotation();
- }
- /*else //set to the root object
- {
- mGridRotation = root->getRenderRotation();
- }*/
- }
- else if (mGridMode == GRID_MODE_REF_OBJECT && first_grid_object && first_grid_object->mDrawable.notNull())
- {
- LLSelectNode *node = mSelectedObjects->findNode(first_grid_object);
- if (!for_snap_guides && node)
- {
- mGridRotation = node->mSavedRotation;
- }
- else
- {
- mGridRotation = first_grid_object->getRenderRotation();
- }
-
- LLVector4a min_extents(F32_MAX);
- LLVector4a max_extents(-F32_MAX);
- bool grid_changed = false;
- for (LLObjectSelection::iterator iter = mGridObjects.begin();
- iter != mGridObjects.end(); ++iter)
- {
- LLViewerObject* object = (*iter)->getObject();
- LLDrawable* drawable = object->mDrawable;
- if (drawable)
- {
- const LLVector4a* ext = drawable->getSpatialExtents();
- update_min_max(min_extents, max_extents, ext[0]);
- update_min_max(min_extents, max_extents, ext[1]);
- grid_changed = true;
- }
- }
- if (grid_changed)
- {
- LLVector4a center, size;
- center.setAdd(min_extents, max_extents);
- center.mul(0.5f);
- size.setSub(max_extents, min_extents);
- size.mul(0.5f);
-
- mGridOrigin.set(center.getF32ptr());
- LLDrawable* drawable = first_grid_object->mDrawable;
- if (drawable && drawable->isActive())
- {
- mGridOrigin = mGridOrigin * first_grid_object->getRenderMatrix();
- }
- mGridScale.set(size.getF32ptr());
- }
- }
- else // GRID_MODE_WORLD or just plain default
- {
- const bool non_root_ok = true;
- LLViewerObject* first_object = mSelectedObjects->getFirstRootObject(non_root_ok);
-
- mGridOrigin.clearVec();
- mGridRotation.loadIdentity();
-
- mSelectedObjects->mSelectType = getSelectTypeForObject( first_object );
-
- switch (mSelectedObjects->mSelectType)
- {
- case SELECT_TYPE_ATTACHMENT:
- if (first_object && first_object->getRootEdit()->mDrawable.notNull())
- {
- // this means this object *has* to be an attachment
- LLXform* attachment_point_xform = first_object->getRootEdit()->mDrawable->mXform.getParent();
- mGridOrigin = attachment_point_xform->getWorldPosition();
- mGridRotation = attachment_point_xform->getWorldRotation();
- mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution");
- }
- break;
- case SELECT_TYPE_HUD:
- mGridScale = LLVector3(1.f, 1.f, 1.f) * llmin(gSavedSettings.getF32("GridResolution"), 0.5f);
- break;
- case SELECT_TYPE_WORLD:
- mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution");
- break;
- }
- }
- llassert(mGridOrigin.isFinite());
-
- origin = mGridOrigin;
- rotation = mGridRotation;
- scale = mGridScale;
-}
-
-//-----------------------------------------------------------------------------
-// remove() - an array of objects
-//-----------------------------------------------------------------------------
-
-void LLSelectMgr::remove(std::vector<LLViewerObject*>& objects)
-{
- for (std::vector<LLViewerObject*>::iterator iter = objects.begin();
- iter != objects.end(); ++iter)
- {
- LLViewerObject* objectp = *iter;
- LLSelectNode* nodep = mSelectedObjects->findNode(objectp);
- if (nodep)
- {
- objectp->setSelected(false);
- mSelectedObjects->removeNode(nodep);
- nodep = NULL;
- }
- }
- updateSelectionCenter();
- dialog_refresh_all();
-}
-
-
-//-----------------------------------------------------------------------------
-// remove() - a single object
-//-----------------------------------------------------------------------------
-void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, bool undoable)
-{
- // get object node (and verify it is in the selected list)
- LLSelectNode *nodep = mSelectedObjects->findNode(objectp);
- if (!nodep)
- {
- return;
- }
-
- // if face = all, remove object from list
- if ((objectp->getNumTEs() <= 0) || (te == SELECT_ALL_TES))
- {
- // Remove all faces (or the object doesn't have faces) so remove the node
- mSelectedObjects->removeNode(nodep);
- nodep = NULL;
- objectp->setSelected( false );
- }
- else if (0 <= te && te < SELECT_MAX_TES)
- {
- // ...valid face, check to see if it was on
- if (nodep->isTESelected(te))
- {
- nodep->selectTE(te, false);
- objectp->setTESelected(te, false);
- }
- else
- {
- LL_ERRS() << "LLSelectMgr::remove - tried to remove TE " << te << " that wasn't selected" << LL_ENDL;
- return;
- }
-
- // ...check to see if this operation turned off all faces
- bool found = false;
- for (S32 i = 0; i < nodep->getObject()->getNumTEs(); i++)
- {
- found = found || nodep->isTESelected(i);
- }
-
- // ...all faces now turned off, so remove
- if (!found)
- {
- mSelectedObjects->removeNode(nodep);
- nodep = NULL;
- objectp->setSelected( false );
- // *FIXME: Doesn't update simulator that object is no longer selected
- }
- }
- else
- {
- // ...out of range face
- LL_ERRS() << "LLSelectMgr::remove - TE " << te << " out of range" << LL_ENDL;
- }
-
- updateSelectionCenter();
- dialog_refresh_all();
-}
-
-
-//-----------------------------------------------------------------------------
-// removeAll()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::removeAll()
-{
- for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
- iter != mSelectedObjects->end(); iter++ )
- {
- LLViewerObject *objectp = (*iter)->getObject();
- objectp->setSelected( false );
- }
-
- mSelectedObjects->deleteAllNodes();
-
- updateSelectionCenter();
- dialog_refresh_all();
-}
-
-//-----------------------------------------------------------------------------
-// promoteSelectionToRoot()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::promoteSelectionToRoot()
-{
- std::set<LLViewerObject*> selection_set;
-
- bool selection_changed = false;
-
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); )
- {
- LLObjectSelection::iterator curiter = iter++;
- LLSelectNode* nodep = *curiter;
- LLViewerObject* object = nodep->getObject();
-
- if (nodep->mIndividualSelection)
- {
- selection_changed = true;
- }
-
- LLViewerObject* parentp = object;
- while(parentp->getParent() && !(parentp->isRootEdit()))
- {
- parentp = (LLViewerObject*)parentp->getParent();
- }
-
- selection_set.insert(parentp);
- }
-
- if (selection_changed)
- {
- deselectAll();
-
- std::set<LLViewerObject*>::iterator set_iter;
- for (set_iter = selection_set.begin(); set_iter != selection_set.end(); ++set_iter)
- {
- selectObjectAndFamily(*set_iter);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// demoteSelectionToIndividuals()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::demoteSelectionToIndividuals()
-{
- std::vector<LLViewerObject*> objects;
-
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++)
- {
- LLViewerObject* object = (*iter)->getObject();
- object->addThisAndNonJointChildren(objects);
- }
-
- if (!objects.empty())
- {
- deselectAll();
- for (std::vector<LLViewerObject*>::iterator iter = objects.begin();
- iter != objects.end(); ++iter)
- {
- LLViewerObject* objectp = *iter;
- selectObjectOnly(objectp);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// dump()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::dump()
-{
- LL_INFOS() << "Selection Manager: " << mSelectedObjects->getNumNodes() << " items" << LL_ENDL;
-
- LL_INFOS() << "TE mode " << mTEMode << LL_ENDL;
-
- S32 count = 0;
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLViewerObject* objectp = (*iter)->getObject();
- LL_INFOS() << "Object " << count << " type " << LLPrimitive::pCodeToString(objectp->getPCode()) << LL_ENDL;
- LL_INFOS() << " hasLSL " << objectp->flagScripted() << LL_ENDL;
- LL_INFOS() << " hasTouch " << objectp->flagHandleTouch() << LL_ENDL;
- LL_INFOS() << " hasMoney " << objectp->flagTakesMoney() << LL_ENDL;
- LL_INFOS() << " getposition " << objectp->getPosition() << LL_ENDL;
- LL_INFOS() << " getpositionAgent " << objectp->getPositionAgent() << LL_ENDL;
- LL_INFOS() << " getpositionRegion " << objectp->getPositionRegion() << LL_ENDL;
- LL_INFOS() << " getpositionGlobal " << objectp->getPositionGlobal() << LL_ENDL;
- LLDrawable* drawablep = objectp->mDrawable;
- LL_INFOS() << " " << (drawablep&& drawablep->isVisible() ? "visible" : "invisible") << LL_ENDL;
- LL_INFOS() << " " << (drawablep&& drawablep->isState(LLDrawable::FORCE_INVISIBLE) ? "force_invisible" : "") << LL_ENDL;
- count++;
- }
-
- // Face iterator
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* objectp = node->getObject();
- if (!objectp)
- continue;
- for (S32 te = 0; te < objectp->getNumTEs(); ++te )
- {
- if (node->isTESelected(te))
- {
- LL_INFOS() << "Object " << objectp << " te " << te << LL_ENDL;
- }
- }
- }
-
- LL_INFOS() << mHighlightedObjects->getNumNodes() << " objects currently highlighted." << LL_ENDL;
-
- LL_INFOS() << "Center global " << mSelectionCenterGlobal << LL_ENDL;
-}
-
-//-----------------------------------------------------------------------------
-// cleanup()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::cleanup()
-{
- mSilhouetteImagep = NULL;
-}
-
-
-//---------------------------------------------------------------------------
-// Manipulate properties of selected objects
-//---------------------------------------------------------------------------
-
-struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor
-{
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->sendTEUpdate();
- }
- return true;
- }
-};
-
-void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item)
-{
- if (!item)
- {
- return;
- }
- LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID());
-
- for (iterator iter = begin(); iter != end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = (*iter)->getObject();
- if (!object)
- {
- continue;
- }
-
- S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
- bool texture_copied = false;
- bool updated = false;
- for (S32 te = 0; te < num_tes; ++te)
- {
- if (node->isTESelected(te))
- {
- //(no-copy) textures must be moved to the object's inventory only once
- // without making any copies
- if (!texture_copied)
- {
- LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
- texture_copied = true;
- }
-
- // apply texture for the selected faces
- add(LLStatViewer::EDIT_TEXTURE, 1);
- object->setTEImage(te, image);
- updated = true;
- }
- }
-
- if (updated) // not nessesary? sendTEUpdate update supposed to be done by sendfunc
- {
- dialog_refresh_all();
-
- // send the update to the simulator
- object->sendTEUpdate();
- }
- }
-}
-
-bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item)
-{
- if (!item)
- {
- return false;
- }
-
- LLUUID asset_id = item->getAssetUUID();
- if (asset_id.isNull())
- {
- asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
- }
-
- bool material_copied_all_faces = true;
-
- for (iterator iter = begin(); iter != end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = (*iter)->getObject();
- if (!object)
- {
- continue;
- }
-
- S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
- bool material_copied = false;
- for (S32 te = 0; te < num_tes; ++te)
- {
- if (node->isTESelected(te))
- {
- //(no-copy), (no-modify), and (no-transfer) materials must be moved to the object's inventory only once
- // without making any copies
- if (!material_copied && asset_id.notNull())
- {
- material_copied = (bool)LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
- }
- if (!material_copied)
- {
- // Applying the material is not possible for this object given the current inventory
- material_copied_all_faces = false;
- break;
- }
-
- // apply texture for the selected faces
- // blank out most override data on the server
- //add(LLStatViewer::EDIT_TEXTURE, 1);
- object->setRenderMaterialID(te, asset_id);
- }
- }
- }
-
- LLGLTFMaterialList::flushUpdates();
-
- return material_copied_all_faces;
-}
-
-
-//-----------------------------------------------------------------------------
-// selectionSetImage()
-//-----------------------------------------------------------------------------
-// *TODO: re-arch texture applying out of lltooldraganddrop
-bool LLSelectMgr::selectionSetImage(const LLUUID& imageid)
-{
- // First for (no copy) textures and multiple object selection
- LLViewerInventoryItem* item = gInventory.getItem(imageid);
- if(item
- && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
- && (mSelectedObjects->getNumNodes() > 1) )
- {
- LL_DEBUGS() << "Attempted to apply no-copy texture " << imageid
- << " to multiple objects" << LL_ENDL;
-
- LLNotificationsUtil::add("FailedToApplyTextureNoCopyToMultiple");
- return false;
- }
-
- struct f : public LLSelectedTEFunctor
- {
- LLViewerInventoryItem* mItem;
- LLUUID mImageID;
- f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {}
- bool apply(LLViewerObject* objectp, S32 te)
- {
- if(!objectp || !objectp->permModify())
- {
- return false;
- }
-
- // Might be better to run willObjectAcceptInventory
- if (mItem && objectp->isAttachment())
- {
- const LLPermissions& perm = mItem->getPermissions();
- bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED;
- if (!unrestricted)
- {
- // Attachments are in world and in inventory simultaneously,
- // at the moment server doesn't support such a situation.
- return false;
- }
- }
-
- if (mItem)
- {
- LLToolDragAndDrop::dropTextureOneFace(objectp,
- te,
- mItem,
- LLToolDragAndDrop::SOURCE_AGENT,
- LLUUID::null,
- false);
- }
- else // not an inventory item
- {
- // Texture picker defaults aren't inventory items
- // * Don't need to worry about permissions for them
- // * Can just apply the texture and be done with it.
- objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
- }
-
- return true;
- }
- };
-
- if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
- {
- getSelection()->applyNoCopyTextureToTEs(item);
- }
- else
- {
- f setfunc(item, imageid);
- getSelection()->applyToTEs(&setfunc);
- }
-
-
- struct g : public LLSelectedObjectFunctor
- {
- LLViewerInventoryItem* mItem;
- g(LLViewerInventoryItem* item) : mItem(item) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (!mItem)
- {
- object->sendTEUpdate();
- // 1 particle effect per object
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, true);
- effectp->setSourceObject(gAgentAvatarp);
- effectp->setTargetObject(object);
- effectp->setDuration(LL_HUD_DUR_SHORT);
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- }
- return true;
- }
- } sendfunc(item);
- getSelection()->applyToObjects(&sendfunc);
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectionSetGLTFMaterial()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
-{
- // First for (no copy) textures and multiple object selection
- LLViewerInventoryItem* item = gInventory.getItem(mat_id);
- if (item
- && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
- && (mSelectedObjects->getNumNodes() > 1))
- {
- LL_DEBUGS() << "Attempted to apply no-copy material " << mat_id
- << "to multiple objects" << LL_ENDL;
-
- LLNotificationsUtil::add("FailedToApplyGLTFNoCopyToMultiple");
- return false;
- }
-
- struct f : public LLSelectedTEFunctor
- {
- LLViewerInventoryItem* mItem;
- LLUUID mMatId;
- bool material_copied_any_face = false;
- bool material_copied_all_faces = true;
- f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mMatId(id) {}
- bool apply(LLViewerObject* objectp, S32 te)
- {
- if (!objectp || !objectp->permModify())
- {
- return false;
- }
- LLUUID asset_id = mMatId;
- if (mItem)
- {
- const LLPermissions& perm = mItem->getPermissions();
- bool from_library = perm.getOwner() == ALEXANDRIA_LINDEN_ID;
- if (objectp->isAttachment())
- {
- bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED;
-
- if (!unrestricted && !from_library)
- {
- // Attachments are in world and in inventory simultaneously,
- // at the moment server doesn't support such a situation.
- return false;
- }
- }
-
- if (!from_library
- // Check if item may be copied into the object's inventory
- && !LLToolDragAndDrop::handleDropMaterialProtections(objectp, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null))
- {
- return false;
- }
-
- asset_id = mItem->getAssetUUID();
- if (asset_id.isNull())
- {
- asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
- }
- }
-
- // Blank out most override data on the object and send to server
- objectp->setRenderMaterialID(te, asset_id);
-
- return true;
- }
- };
-
- bool success = true;
- if (item
- && (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) ||
- !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) ||
- !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID())
- )
- && item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID
- )
- {
- success = success && getSelection()->applyRestrictedPbrMaterialToTEs(item);
- }
- else
- {
- f setfunc(item, mat_id);
- success = success && getSelection()->applyToTEs(&setfunc);
- }
-
- struct g : public LLSelectedObjectFunctor
- {
- LLViewerInventoryItem* mItem;
- g(LLViewerInventoryItem* item) : mItem(item) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object && !object->permModify())
- {
- return false;
- }
-
- if (!mItem)
- {
- // 1 particle effect per object
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, true);
- effectp->setSourceObject(gAgentAvatarp);
- effectp->setTargetObject(object);
- effectp->setDuration(LL_HUD_DUR_SHORT);
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- }
-
- dialog_refresh_all();
- object->sendTEUpdate();
- return true;
- }
- } sendfunc(item);
- success = success && getSelection()->applyToObjects(&sendfunc);
-
- LLGLTFMaterialList::flushUpdates();
-
- return success;
-}
-
-//-----------------------------------------------------------------------------
-// selectionSetColor()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::selectionSetColor(const LLColor4 &color)
-{
- struct f : public LLSelectedTEFunctor
- {
- LLColor4 mColor;
- f(const LLColor4& c) : mColor(c) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- object->setTEColor(te, mColor);
- }
- return true;
- }
- } setfunc(color);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-//-----------------------------------------------------------------------------
-// selectionSetColorOnly()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::selectionSetColorOnly(const LLColor4 &color)
-{
- struct f : public LLSelectedTEFunctor
- {
- LLColor4 mColor;
- f(const LLColor4& c) : mColor(c) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- LLColor4 prev_color = object->getTE(te)->getColor();
- mColor.mV[VALPHA] = prev_color.mV[VALPHA];
- // update viewer side color in anticipation of update from simulator
- object->setTEColor(te, mColor);
- }
- return true;
- }
- } setfunc(color);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-//-----------------------------------------------------------------------------
-// selectionSetAlphaOnly()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::selectionSetAlphaOnly(const F32 alpha)
-{
- struct f : public LLSelectedTEFunctor
- {
- F32 mAlpha;
- f(const F32& a) : mAlpha(a) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- LLColor4 prev_color = object->getTE(te)->getColor();
- prev_color.mV[VALPHA] = mAlpha;
- // update viewer side color in anticipation of update from simulator
- object->setTEColor(te, prev_color);
- }
- return true;
- }
- } setfunc(alpha);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionRevertColors()
-{
- struct f : public LLSelectedTEFunctor
- {
- LLObjectSelectionHandle mSelectedObjects;
- f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- LLSelectNode* nodep = mSelectedObjects->findNode(object);
- if (nodep && te < (S32)nodep->mSavedColors.size())
- {
- LLColor4 color = nodep->mSavedColors[te];
- // update viewer side color in anticipation of update from simulator
- object->setTEColor(te, color);
- }
- }
- return true;
- }
- } setfunc(mSelectedObjects);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionRevertShinyColors()
-{
- struct f : public LLSelectedTEFunctor
- {
- LLObjectSelectionHandle mSelectedObjects;
- f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- LLSelectNode* nodep = mSelectedObjects->findNode(object);
- if (nodep && te < (S32)nodep->mSavedShinyColors.size())
- {
- LLColor4 color = nodep->mSavedShinyColors[te];
- // update viewer side color in anticipation of update from simulator
- LLMaterialPtr old_mat = object->getTE(te)->getMaterialParams();
- if (!old_mat.isNull())
- {
- LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat);
- new_mat->setSpecularLightColor(color);
- object->getTE(te)->setMaterialParams(new_mat);
- LLMaterialMgr::getInstance()->put(object->getID(), te, *new_mat);
- }
- }
- }
- return true;
- }
- } setfunc(mSelectedObjects);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-bool LLSelectMgr::selectionRevertTextures()
-{
- struct f : public LLSelectedTEFunctor
- {
- LLObjectSelectionHandle mSelectedObjects;
- f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- LLSelectNode* nodep = mSelectedObjects->findNode(object);
- if (nodep && te < (S32)nodep->mSavedTextures.size())
- {
- LLUUID id = nodep->mSavedTextures[te];
- // update textures on viewer side
- if (id.isNull())
- {
- // this was probably a no-copy texture, leave image as-is
- return false;
- }
- else
- {
- object->setTEImage(te, LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
-
- }
- }
- }
- return true;
- }
- } setfunc(mSelectedObjects);
- bool revert_successful = getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-
- return revert_successful;
-}
-
-void LLSelectMgr::selectionRevertGLTFMaterials()
-{
- struct f : public LLSelectedTEFunctor
- {
- LLObjectSelectionHandle mSelectedObjects;
- f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {}
- bool apply(LLViewerObject* objectp, S32 te)
- {
- if (objectp && !objectp->permModify())
- {
- return false;
- }
-
- LLSelectNode* nodep = mSelectedObjects->findNode(objectp);
- if (nodep && te < (S32)nodep->mSavedGLTFMaterialIds.size())
- {
- // Restore base material
- LLUUID asset_id = nodep->mSavedGLTFMaterialIds[te];
-
- // Update material locally
- objectp->setRenderMaterialID(te, asset_id, false /*wait for LLGLTFMaterialList update*/);
- objectp->setTEGLTFMaterialOverride(te, nodep->mSavedGLTFOverrideMaterials[te]);
-
- // Enqueue update to server
- if (asset_id.notNull())
- {
- // Restore overrides and base material
- LLGLTFMaterialList::queueApply(objectp, te, asset_id, nodep->mSavedGLTFOverrideMaterials[te]);
- }
- else
- {
- //blank override out
- LLGLTFMaterialList::queueApply(objectp, te, asset_id);
- }
-
- }
- return true;
- }
- } setfunc(mSelectedObjects);
- getSelection()->applyToTEs(&setfunc);
-}
-
-void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id)
-{
- struct f : public LLSelectedTEFunctor
- {
- U8 mBump;
- f(const U8& b) : mBump(b) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- // update viewer side color in anticipation of update from simulator
- object->setTEBumpmap(te, mBump);
- }
- return true;
- }
- } setfunc(bumpmap);
-
- LLViewerInventoryItem* item = gInventory.getItem(image_id);
- if(item
- && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
- && (mSelectedObjects->getNumNodes() > 1) )
- {
- LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL;
- return;
- }
-
- if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
- {
- LLViewerObject *object = mSelectedObjects->getFirstRootObject();
- if (!object)
- {
- return;
- }
- const LLPermissions& perm = item->getPermissions();
- bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED;
- bool attached = object->isAttachment();
- if (attached && !unrestricted)
- {
- // Attachments are in world and in inventory simultaneously,
- // at the moment server doesn't support such a situation.
- return;
- }
- LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
- }
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionSetTexGen(U8 texgen)
-{
- struct f : public LLSelectedTEFunctor
- {
- U8 mTexgen;
- f(const U8& t) : mTexgen(t) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- // update viewer side color in anticipation of update from simulator
- object->setTETexGen(te, mTexgen);
- }
- return true;
- }
- } setfunc(texgen);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-
-void LLSelectMgr::selectionSetShiny(U8 shiny, const LLUUID &image_id)
-{
- struct f : public LLSelectedTEFunctor
- {
- U8 mShiny;
- f(const U8& t) : mShiny(t) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- // update viewer side color in anticipation of update from simulator
- object->setTEShiny(te, mShiny);
- }
- return true;
- }
- } setfunc(shiny);
-
- LLViewerInventoryItem* item = gInventory.getItem(image_id);
- if(item
- && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
- && (mSelectedObjects->getNumNodes() > 1) )
- {
- LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL;
- return;
- }
-
- if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
- {
- LLViewerObject *object = mSelectedObjects->getFirstRootObject();
- if (!object)
- {
- return;
- }
- const LLPermissions& perm = item->getPermissions();
- bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED;
- bool attached = object->isAttachment();
- if (attached && !unrestricted)
- {
- // Attachments are in world and in inventory simultaneously,
- // at the moment server doesn't support such a situation.
- return;
- }
- LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
- }
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionSetFullbright(U8 fullbright)
-{
- struct f : public LLSelectedTEFunctor
- {
- U8 mFullbright;
- f(const U8& t) : mFullbright(t) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- // update viewer side color in anticipation of update from simulator
- object->setTEFullbright(te, mFullbright);
- }
- return true;
- }
- } setfunc(fullbright);
- getSelection()->applyToTEs(&setfunc);
-
- struct g : public LLSelectedObjectFunctor
- {
- U8 mFullbright;
- g(const U8& t) : mFullbright(t) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->sendTEUpdate();
- if (mFullbright)
- {
- U8 material = object->getMaterial();
- U8 mcode = material & LL_MCODE_MASK;
- if (mcode == LL_MCODE_LIGHT)
- {
- mcode = LL_MCODE_GLASS;
- material = (material & ~LL_MCODE_MASK) | mcode;
- object->setMaterial(material);
- object->sendMaterialUpdate();
- }
- }
- }
- return true;
- }
- } sendfunc(fullbright);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-// This function expects media_data to be a map containing relevant
-// media data name/value pairs (e.g. home_url, etc.)
-void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data)
-{
- struct f : public LLSelectedTEFunctor
- {
- U8 mMediaFlags;
- const LLSD &mMediaData;
- f(const U8& t, const LLSD& d) : mMediaFlags(t), mMediaData(d) {}
- bool apply(LLViewerObject* object, S32 te)
- {
- if (object->permModify())
- {
- // If we are adding media, then check the current state of the
- // media data on this face.
- // - If it does not have media, AND we are NOT setting the HOME URL, then do NOT add media to this
- // face.
- // - If it does not have media, and we ARE setting the HOME URL, add media to this face.
- // - If it does already have media, add/update media to/on this face
- // If we are removing media, just do it (ignore the passed-in LLSD).
- if (mMediaFlags & LLTextureEntry::MF_HAS_MEDIA)
- {
- llassert(mMediaData.isMap());
- const LLTextureEntry *texture_entry = object->getTE(te);
- if (!mMediaData.isMap() ||
- ((NULL != texture_entry) && !texture_entry->hasMedia() && !mMediaData.has(LLMediaEntry::HOME_URL_KEY)))
- {
- // skip adding/updating media
- }
- else {
- // Add/update media
- object->setTEMediaFlags(te, mMediaFlags);
- LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
- llassert(NULL != vo);
- if (NULL != vo)
- {
- vo->syncMediaData(te, mMediaData, true/*merge*/, true/*ignore_agent*/);
- }
- }
- }
- else
- {
- // delete media (or just set the flags)
- object->setTEMediaFlags(te, mMediaFlags);
- }
- }
- return true;
- }
- } setfunc(media_type, media_data);
- getSelection()->applyToTEs(&setfunc);
-
- struct f2 : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->sendTEUpdate();
- LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object);
- llassert(NULL != vo);
- // It's okay to skip this object if hasMedia() is false...
- // the sendTEUpdate() above would remove all media data if it were
- // there.
- if (NULL != vo && vo->hasMedia())
- {
- // Send updated media data FOR THE ENTIRE OBJECT
- vo->sendMediaDataUpdate();
- }
- }
- return true;
- }
- } func2;
- mSelectedObjects->applyToObjects( &func2 );
-}
-
-void LLSelectMgr::selectionSetGlow(F32 glow)
-{
- struct f1 : public LLSelectedTEFunctor
- {
- F32 mGlow;
- f1(F32 glow) : mGlow(glow) {};
- bool apply(LLViewerObject* object, S32 face)
- {
- if (object->permModify())
- {
- // update viewer side color in anticipation of update from simulator
- object->setTEGlow(face, mGlow);
- }
- return true;
- }
- } func1(glow);
- mSelectedObjects->applyToTEs( &func1 );
-
- struct f2 : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->sendTEUpdate();
- }
- return true;
- }
- } func2;
- mSelectedObjects->applyToObjects( &func2 );
-}
-
-void LLSelectMgr::selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func, int te)
-{
- struct f1 : public LLSelectedTEFunctor
- {
- LLMaterialPtr mMaterial;
- f1(LLSelectedTEMaterialFunctor* material_func, int te) : _material_func(material_func), _specific_te(te) {}
-
- bool apply(LLViewerObject* object, S32 te)
- {
- if (_specific_te == -1 || (te == _specific_te))
- {
- if (object && object->permModify() && _material_func)
- {
- LLTextureEntry* tep = object->getTE(te);
- if (tep)
- {
- LLMaterialPtr current_material = tep->getMaterialParams();
- _material_func->apply(object, te, tep, current_material);
- }
- }
- }
- return true;
- }
-
- LLSelectedTEMaterialFunctor* _material_func;
- int _specific_te;
- } func1(material_func, te);
- mSelectedObjects->applyToTEs( &func1 );
-
- struct f2 : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->sendTEUpdate();
- }
- return true;
- }
- } func2;
- mSelectedObjects->applyToObjects( &func2 );
-}
-
-void LLSelectMgr::selectionRemoveMaterial()
-{
- struct f1 : public LLSelectedTEFunctor
- {
- bool apply(LLViewerObject* object, S32 face)
- {
- if (object->permModify())
- {
- LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
- LLMaterialMgr::getInstance()->remove(object->getID(),face);
- object->setTEMaterialParams(face, NULL);
- }
- return true;
- }
- } func1;
- mSelectedObjects->applyToTEs( &func1 );
-
- struct f2 : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->sendTEUpdate();
- }
- return true;
- }
- } func2;
- mSelectedObjects->applyToObjects( &func2 );
-}
-
-
-//-----------------------------------------------------------------------------
-// findObjectPermissions()
-//-----------------------------------------------------------------------------
-LLPermissions* LLSelectMgr::findObjectPermissions(const LLViewerObject* object)
-{
- for (LLObjectSelection::valid_iterator iter = getSelection()->valid_begin();
- iter != getSelection()->valid_end(); iter++ )
- {
- LLSelectNode* nodep = *iter;
- if (nodep->getObject() == object)
- {
- return nodep->mPermissions;
- }
- }
-
- return NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// selectionGetGlow()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectionGetGlow(F32 *glow)
-{
- bool identical;
- F32 lglow = 0.f;
- struct f1 : public LLSelectedTEGetFunctor<F32>
- {
- F32 get(LLViewerObject* object, S32 face)
- {
- return object->getTE(face)->getGlow();
- }
- } func;
- identical = mSelectedObjects->getSelectedTEValue( &func, lglow );
-
- *glow = lglow;
- return identical;
-}
-
-
-void LLSelectMgr::selectionSetPhysicsType(U8 type)
-{
- struct f : public LLSelectedObjectFunctor
- {
- U8 mType;
- f(const U8& t) : mType(t) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->setPhysicsShapeType(mType);
- object->updateFlags(true);
- }
- return true;
- }
- } sendfunc(type);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionSetFriction(F32 friction)
-{
- struct f : public LLSelectedObjectFunctor
- {
- F32 mFriction;
- f(const F32& friction) : mFriction(friction) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->setPhysicsFriction(mFriction);
- object->updateFlags(true);
- }
- return true;
- }
- } sendfunc(friction);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionSetGravity(F32 gravity )
-{
- struct f : public LLSelectedObjectFunctor
- {
- F32 mGravity;
- f(const F32& gravity) : mGravity(gravity) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->setPhysicsGravity(mGravity);
- object->updateFlags(true);
- }
- return true;
- }
- } sendfunc(gravity);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionSetDensity(F32 density )
-{
- struct f : public LLSelectedObjectFunctor
- {
- F32 mDensity;
- f(const F32& density ) : mDensity(density) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->setPhysicsDensity(mDensity);
- object->updateFlags(true);
- }
- return true;
- }
- } sendfunc(density);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-void LLSelectMgr::selectionSetRestitution(F32 restitution)
-{
- struct f : public LLSelectedObjectFunctor
- {
- F32 mRestitution;
- f(const F32& restitution ) : mRestitution(restitution) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- object->setPhysicsRestitution(mRestitution);
- object->updateFlags(true);
- }
- return true;
- }
- } sendfunc(restitution);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-
-//-----------------------------------------------------------------------------
-// selectionSetMaterial()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::selectionSetMaterial(U8 material)
-{
- struct f : public LLSelectedObjectFunctor
- {
- U8 mMaterial;
- f(const U8& t) : mMaterial(t) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- U8 cur_material = object->getMaterial();
- U8 material = mMaterial | (cur_material & ~LL_MCODE_MASK);
- object->setMaterial(material);
- object->sendMaterialUpdate();
- }
- return true;
- }
- } sendfunc(material);
- getSelection()->applyToObjects(&sendfunc);
-}
-
-// true if all selected objects have this PCode
-bool LLSelectMgr::selectionAllPCode(LLPCode code)
-{
- struct f : public LLSelectedObjectFunctor
- {
- LLPCode mCode;
- f(const LLPCode& t) : mCode(t) {}
- virtual bool apply(LLViewerObject* object)
- {
- if (object->getPCode() != mCode)
- {
- return false;
- }
- return true;
- }
- } func(code);
- bool res = getSelection()->applyToObjects(&func);
- return res;
-}
-
-bool LLSelectMgr::selectionGetIncludeInSearch(bool* include_in_search_out)
-{
- LLViewerObject *object = mSelectedObjects->getFirstRootObject();
- if (!object) return false;
-
- bool include_in_search = object->getIncludeInSearch();
-
- bool identical = true;
-
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++)
- {
- LLViewerObject* object = (*iter)->getObject();
-
- if ( include_in_search != object->getIncludeInSearch())
- {
- identical = false;
- break;
- }
- }
-
- *include_in_search_out = include_in_search;
- return identical;
-}
-
-void LLSelectMgr::selectionSetIncludeInSearch(bool include_in_search)
-{
- LLViewerObject* object = NULL;
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++)
- {
- object = (*iter)->getObject();
- object->setIncludeInSearch(include_in_search);
- }
- sendListToRegions(
- "ObjectIncludeInSearch",
- packAgentAndSessionID,
- packObjectIncludeInSearch,
- logNoOp,
- &include_in_search,
- SEND_ONLY_ROOTS);
-}
-
-bool LLSelectMgr::selectionGetClickAction(U8 *out_action)
-{
- LLViewerObject *object = mSelectedObjects->getFirstObject();
- if (!object)
- {
- return false;
- }
-
- U8 action = object->getClickAction();
- *out_action = action;
-
- struct f : public LLSelectedObjectFunctor
- {
- U8 mAction;
- f(const U8& t) : mAction(t) {}
- virtual bool apply(LLViewerObject* object)
- {
- if ( mAction != object->getClickAction())
- {
- return false;
- }
- return true;
- }
- } func(action);
- bool res = getSelection()->applyToObjects(&func);
- return res;
-}
-
-void LLSelectMgr::selectionSetClickAction(U8 action)
-{
- struct f : public LLSelectedObjectFunctor
- {
- U8 mAction;
- f(const U8& t) : mAction(t) {}
- virtual bool apply(LLViewerObject* object)
- {
- object->setClickAction(mAction);
- return true;
- }
- } func(action);
- getSelection()->applyToObjects(&func);
-
- sendListToRegions("ObjectClickAction",
- packAgentAndSessionID,
- packObjectClickAction,
- logNoOp,
- &action,
- SEND_INDIVIDUALS);
-}
-
-
-//-----------------------------------------------------------------------------
-// godlike requests
-//-----------------------------------------------------------------------------
-
-typedef std::pair<const std::string, const std::string> godlike_request_t;
-
-void LLSelectMgr::sendGodlikeRequest(const std::string& request, const std::string& param)
-{
- // If the agent is neither godlike nor an estate owner, the server
- // will reject the request.
- std::string message_type;
- if (gAgent.isGodlike())
- {
- message_type = "GodlikeMessage";
- }
- else
- {
- message_type = "EstateOwnerMessage";
- }
-
- godlike_request_t data(request, param);
- if(!mSelectedObjects->getRootObjectCount())
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage(message_type.c_str());
- LLSelectMgr::packGodlikeHead(&data);
- gAgent.sendReliableMessage();
- }
- else
- {
- sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, logNoOp, &data, SEND_ONLY_ROOTS);
- }
-}
-
-void LLSelectMgr::packGodlikeHead(void* user_data)
-{
- LLMessageSystem* msg = gMessageSystem;
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUID("TransactionID", LLUUID::null);
- godlike_request_t* data = (godlike_request_t*)user_data;
- msg->nextBlock("MethodData");
- msg->addString("Method", data->first);
- msg->addUUID("Invoice", LLUUID::null);
-
- // The parameters used to be restricted to either string or
- // integer. This mimics that behavior under the new 'string-only'
- // parameter list by not packing a string if there wasn't one
- // specified. The object ids will be packed in the
- // packObjectIDAsParam() method.
- if(data->second.size() > 0)
- {
- msg->nextBlock("ParamList");
- msg->addString("Parameter", data->second);
- }
-}
-
-// static
-void LLSelectMgr::logNoOp(LLSelectNode* node, void *)
-{
-}
-
-// static
-void LLSelectMgr::logAttachmentRequest(LLSelectNode* node, void *)
-{
- LLAttachmentsMgr::instance().onAttachmentRequested(node->mItemID);
-}
-
-// static
-void LLSelectMgr::logDetachRequest(LLSelectNode* node, void *)
-{
- LLAttachmentsMgr::instance().onDetachRequested(node->mItemID);
-}
-
-// static
-void LLSelectMgr::packObjectIDAsParam(LLSelectNode* node, void *)
-{
- std::string buf = llformat("%u", node->getObject()->getLocalID());
- gMessageSystem->nextBlock("ParamList");
- gMessageSystem->addString("Parameter", buf);
-}
-
-//-----------------------------------------------------------------------------
-// selectionTexScaleAutofit()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::selectionTexScaleAutofit(F32 repeats_per_meter)
-{
- struct f : public LLSelectedTEFunctor
- {
- F32 mRepeatsPerMeter;
- f(const F32& t) : mRepeatsPerMeter(t) {}
- bool apply(LLViewerObject* object, S32 te)
- {
-
- if (object->permModify())
- {
- // Compute S,T to axis mapping
- U32 s_axis, t_axis;
- if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
- {
- return true;
- }
-
- F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter;
- F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter;
-
- object->setTEScale(te, new_s, new_t);
- }
- return true;
- }
- } setfunc(repeats_per_meter);
- getSelection()->applyToTEs(&setfunc);
-
- LLSelectMgrSendFunctor sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-}
-
-
-
-// Called at the end of a scale operation, this adjusts the textures to attempt to
-// maintain a constant repeats per meter.
-// BUG: Only works for flex boxes.
-//-----------------------------------------------------------------------------
-// adjustTexturesByScale()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::adjustTexturesByScale(bool send_to_sim, bool stretch)
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* object = selectNode->getObject();
-
- if (!object)
- {
- continue;
- }
-
- if (!object->permModify())
- {
- continue;
- }
-
- if (object->getNumTEs() == 0)
- {
- continue;
- }
-
- bool send = false;
-
- for (U8 te_num = 0; te_num < object->getNumTEs(); te_num++)
- {
- const LLTextureEntry* tep = object->getTE(te_num);
-
- bool planar = tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR;
- if (planar == stretch)
- {
- // Figure out how S,T changed with scale operation
- U32 s_axis, t_axis;
- if (!LLPrimitive::getTESTAxes(te_num, &s_axis, &t_axis))
- {
- continue;
- }
-
- LLVector3 object_scale = object->getScale();
- LLVector3 diffuse_scale_ratio = selectNode->mTextureScaleRatios[te_num];
-
- // We like these to track together. NORSPEC-96
- //
- LLVector3 normal_scale_ratio = diffuse_scale_ratio;
- LLVector3 specular_scale_ratio = diffuse_scale_ratio;
-
- // Apply new scale to face
- if (planar)
- {
- F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]/object_scale.mV[s_axis];
- F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]/object_scale.mV[t_axis];
-
- F32 normal_scale_s = normal_scale_ratio.mV[s_axis]/object_scale.mV[s_axis];
- F32 normal_scale_t = normal_scale_ratio.mV[t_axis]/object_scale.mV[t_axis];
-
- F32 specular_scale_s = specular_scale_ratio.mV[s_axis]/object_scale.mV[s_axis];
- F32 specular_scale_t = specular_scale_ratio.mV[t_axis]/object_scale.mV[t_axis];
-
- object->setTEScale(te_num, diffuse_scale_s, diffuse_scale_t);
-
- LLTextureEntry* tep = object->getTE(te_num);
-
- if (tep && !tep->getMaterialParams().isNull())
- {
- LLMaterialPtr orig = tep->getMaterialParams();
- LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
- p->setNormalRepeat(normal_scale_s, normal_scale_t);
- p->setSpecularRepeat(specular_scale_s, specular_scale_t);
-
- LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p);
- }
- }
- else
- {
-
- F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]*object_scale.mV[s_axis];
- F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]*object_scale.mV[t_axis];
-
- F32 normal_scale_s = normal_scale_ratio.mV[s_axis]*object_scale.mV[s_axis];
- F32 normal_scale_t = normal_scale_ratio.mV[t_axis]*object_scale.mV[t_axis];
-
- F32 specular_scale_s = specular_scale_ratio.mV[s_axis]*object_scale.mV[s_axis];
- F32 specular_scale_t = specular_scale_ratio.mV[t_axis]*object_scale.mV[t_axis];
-
- object->setTEScale(te_num, diffuse_scale_s,diffuse_scale_t);
-
- LLTextureEntry* tep = object->getTE(te_num);
-
- if (tep && !tep->getMaterialParams().isNull())
- {
- LLMaterialPtr orig = tep->getMaterialParams();
- LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
-
- p->setNormalRepeat(normal_scale_s, normal_scale_t);
- p->setSpecularRepeat(specular_scale_s, specular_scale_t);
-
- LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p);
- }
- }
- send = send_to_sim;
- }
- }
-
- if (send)
- {
- object->sendTEUpdate();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// selectGetAllRootsValid()
-// Returns true if the viewer has information on all selected objects
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetAllRootsValid()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); ++iter )
- {
- LLSelectNode* node = *iter;
- if( !node->mValid )
- {
- return false;
- }
- }
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// selectGetAllValid()
-// Returns true if the viewer has information on all selected objects
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetAllValid()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); ++iter )
- {
- LLSelectNode* node = *iter;
- if( !node->mValid )
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetAllValidAndObjectsFound() - return true if selections are
-// valid and objects are found.
-//
-// For EXT-3114 - same as selectGetModify() without the modify check.
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetAllValidAndObjectsFound()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetModify() - return true if current agent can modify all
-// selected objects.
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetModify()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( !object->permModify() )
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsModify() - return true if current agent can modify all
-// selected root objects.
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsModify()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( !object->permModify() )
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetSameRegion() - return true if all objects are in same region
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetSameRegion()
-{
- if (getSelection()->isEmpty())
- {
- return true;
- }
- LLViewerObject* object = getSelection()->getFirstObject();
- if (!object)
- {
- return false;
- }
- LLViewerRegion* current_region = object->getRegion();
-
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- object = node->getObject();
- if (!node->mValid || !object || current_region != object->getRegion())
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetNonPermanentEnforced() - return true if all objects are not
-// permanent enforced
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetNonPermanentEnforced()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( object->isPermanentEnforced())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsNonPermanentEnforced() - return true if all root objects are
-// not permanent enforced
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsNonPermanentEnforced()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( object->isPermanentEnforced())
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetPermanent() - return true if all objects are permanent
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetPermanent()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( !object->flagObjectPermanent())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsPermanent() - return true if all root objects are
-// permanent
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsPermanent()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( !object->flagObjectPermanent())
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetCharacter() - return true if all objects are character
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetCharacter()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( !object->flagCharacter())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsCharacter() - return true if all root objects are
-// character
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsCharacter()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( !object->flagCharacter())
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetNonPathfinding() - return true if all objects are not pathfinding
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetNonPathfinding()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( object->flagObjectPermanent() || object->flagCharacter())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsNonPathfinding() - return true if all root objects are not
-// pathfinding
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsNonPathfinding()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( object->flagObjectPermanent() || object->flagCharacter())
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetNonPermanent() - return true if all objects are not permanent
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetNonPermanent()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( object->flagObjectPermanent())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsNonPermanent() - return true if all root objects are not
-// permanent
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsNonPermanent()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( object->flagObjectPermanent())
- {
- return false;
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetNonCharacter() - return true if all objects are not character
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetNonCharacter()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( object->flagCharacter())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsNonCharacter() - return true if all root objects are not
-// character
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsNonCharacter()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if( object->flagCharacter())
- {
- return false;
- }
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-// selectGetEditableLinksets() - return true if all objects are editable
-// pathfinding linksets
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetEditableLinksets()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if (object->flagUsePhysics() ||
- object->flagTemporaryOnRez() ||
- object->flagCharacter() ||
- object->flagVolumeDetect() ||
- object->flagAnimSource() ||
- (object->getRegion() != gAgent.getRegion()) ||
- (!gAgent.isGodlike() &&
- !gAgent.canManageEstate() &&
- !object->permYouOwner() &&
- !object->permMove()))
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetViewableCharacters() - return true if all objects are characters
-// viewable within the pathfinding characters floater
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetViewableCharacters()
-{
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !object || !node->mValid )
- {
- return false;
- }
- if( !object->flagCharacter() ||
- (object->getRegion() != gAgent.getRegion()))
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsTransfer() - return true if current agent can transfer all
-// selected root objects.
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsTransfer()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if(!object->permTransfer())
- {
- return false;
- }
- }
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetRootsCopy() - return true if current agent can copy all
-// selected root objects.
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetRootsCopy()
-{
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if( !node->mValid )
- {
- return false;
- }
- if(!object->permCopy())
- {
- return false;
- }
- }
- return true;
-}
-
-struct LLSelectGetFirstTest
-{
- LLSelectGetFirstTest() : mIdentical(true), mFirst(true) { }
- virtual ~LLSelectGetFirstTest() { }
-
- // returns false to break out of the iteration.
- bool checkMatchingNode(LLSelectNode* node)
- {
- if (!node || !node->mValid)
- {
- return false;
- }
-
- if (mFirst)
- {
- mFirstValue = getValueFromNode(node);
- mFirst = false;
- }
- else
- {
- if ( mFirstValue != getValueFromNode(node) )
- {
- mIdentical = false;
- // stop testing once we know not all selected are identical.
- return false;
- }
- }
- // continue testing.
- return true;
- }
-
- bool mIdentical;
- LLUUID mFirstValue;
-
-protected:
- virtual const LLUUID& getValueFromNode(LLSelectNode* node) = 0;
-
-private:
- bool mFirst;
-};
-
-void LLSelectMgr::getFirst(LLSelectGetFirstTest* test)
-{
- if (gSavedSettings.getBOOL("EditLinkedParts"))
- {
- for (LLObjectSelection::valid_iterator iter = getSelection()->valid_begin();
- iter != getSelection()->valid_end(); ++iter )
- {
- if (!test->checkMatchingNode(*iter))
- {
- break;
- }
- }
- }
- else
- {
- for (LLObjectSelection::root_object_iterator iter = getSelection()->root_object_begin();
- iter != getSelection()->root_object_end(); ++iter )
- {
- if (!test->checkMatchingNode(*iter))
- {
- break;
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// selectGetCreator()
-// Creator information only applies to roots unless editing linked parts.
-//-----------------------------------------------------------------------------
-struct LLSelectGetFirstCreator : public LLSelectGetFirstTest
-{
-protected:
- virtual const LLUUID& getValueFromNode(LLSelectNode* node)
- {
- return node->mPermissions->getCreator();
- }
-};
-
-bool LLSelectMgr::selectGetCreator(LLUUID& result_id, std::string& name)
-{
- LLSelectGetFirstCreator test;
- getFirst(&test);
-
- if (test.mFirstValue.isNull())
- {
- name = LLTrans::getString("AvatarNameNobody");
- return false;
- }
-
- result_id = test.mFirstValue;
-
- if (test.mIdentical)
- {
- name = LLSLURL("agent", test.mFirstValue, "inspect").getSLURLString();
- }
- else
- {
- name = LLTrans::getString("AvatarNameMultiple");
- }
-
- return test.mIdentical;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetOwner()
-// Owner information only applies to roots unless editing linked parts.
-//-----------------------------------------------------------------------------
-struct LLSelectGetFirstOwner : public LLSelectGetFirstTest
-{
-protected:
- virtual const LLUUID& getValueFromNode(LLSelectNode* node)
- {
- // Don't use 'getOwnership' since we return a reference, not a copy.
- // Will return LLUUID::null if unowned (which is not allowed and should never happen.)
- return node->mPermissions->isGroupOwned() ? node->mPermissions->getGroup() : node->mPermissions->getOwner();
- }
-};
-
-bool LLSelectMgr::selectGetOwner(LLUUID& result_id, std::string& name)
-{
- LLSelectGetFirstOwner test;
- getFirst(&test);
-
- if (test.mFirstValue.isNull())
- {
- return false;
- }
-
- result_id = test.mFirstValue;
-
- if (test.mIdentical)
- {
- bool group_owned = selectIsGroupOwned();
- if (group_owned)
- {
- name = LLSLURL("group", test.mFirstValue, "inspect").getSLURLString();
- }
- else
- {
- name = LLSLURL("agent", test.mFirstValue, "inspect").getSLURLString();
- }
- }
- else
- {
- name = LLTrans::getString("AvatarNameMultiple");
- }
-
- return test.mIdentical;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetLastOwner()
-// Owner information only applies to roots unless editing linked parts.
-//-----------------------------------------------------------------------------
-struct LLSelectGetFirstLastOwner : public LLSelectGetFirstTest
-{
-protected:
- virtual const LLUUID& getValueFromNode(LLSelectNode* node)
- {
- return node->mPermissions->getLastOwner();
- }
-};
-
-bool LLSelectMgr::selectGetLastOwner(LLUUID& result_id, std::string& name)
-{
- LLSelectGetFirstLastOwner test;
- getFirst(&test);
-
- if (test.mFirstValue.isNull())
- {
- return false;
- }
-
- result_id = test.mFirstValue;
-
- if (test.mIdentical)
- {
- name = LLSLURL("agent", test.mFirstValue, "inspect").getSLURLString();
- }
- else
- {
- name.assign( "" );
- }
-
- return test.mIdentical;
-}
-
-//-----------------------------------------------------------------------------
-// selectGetGroup()
-// Group information only applies to roots unless editing linked parts.
-//-----------------------------------------------------------------------------
-struct LLSelectGetFirstGroup : public LLSelectGetFirstTest
-{
-protected:
- virtual const LLUUID& getValueFromNode(LLSelectNode* node)
- {
- return node->mPermissions->getGroup();
- }
-};
-
-bool LLSelectMgr::selectGetGroup(LLUUID& result_id)
-{
- LLSelectGetFirstGroup test;
- getFirst(&test);
-
- result_id = test.mFirstValue;
- return test.mIdentical;
-}
-
-//-----------------------------------------------------------------------------
-// selectIsGroupOwned()
-// Only operates on root nodes unless editing linked parts.
-// Returns true if the first selected is group owned.
-//-----------------------------------------------------------------------------
-struct LLSelectGetFirstGroupOwner : public LLSelectGetFirstTest
-{
-protected:
- virtual const LLUUID& getValueFromNode(LLSelectNode* node)
- {
- if (node->mPermissions->isGroupOwned())
- {
- return node->mPermissions->getGroup();
- }
- return LLUUID::null;
- }
-};
-
-bool LLSelectMgr::selectIsGroupOwned()
-{
- LLSelectGetFirstGroupOwner test;
- getFirst(&test);
-
- return test.mFirstValue.notNull();
-}
-
-//-----------------------------------------------------------------------------
-// selectGetPerm()
-// Only operates on root nodes.
-// Returns true if all have valid data.
-// mask_on has bits set to true where all permissions are true
-// mask_off has bits set to true where all permissions are false
-// if a bit is off both in mask_on and mask_off, the values differ within
-// the selection.
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectGetPerm(U8 which_perm, U32* mask_on, U32* mask_off)
-{
- U32 mask;
- U32 mask_and = 0xffffffff;
- U32 mask_or = 0x00000000;
- bool all_valid = false;
-
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
-
- if (!node->mValid)
- {
- all_valid = false;
- break;
- }
-
- all_valid = true;
-
- switch( which_perm )
- {
- case PERM_BASE:
- mask = node->mPermissions->getMaskBase();
- break;
- case PERM_OWNER:
- mask = node->mPermissions->getMaskOwner();
- break;
- case PERM_GROUP:
- mask = node->mPermissions->getMaskGroup();
- break;
- case PERM_EVERYONE:
- mask = node->mPermissions->getMaskEveryone();
- break;
- case PERM_NEXT_OWNER:
- mask = node->mPermissions->getMaskNextOwner();
- break;
- default:
- mask = 0x0;
- break;
- }
- mask_and &= mask;
- mask_or |= mask;
- }
-
- if (all_valid)
- {
- // ...true through all ANDs means all true
- *mask_on = mask_and;
-
- // ...false through all ORs means all false
- *mask_off = ~mask_or;
- return true;
- }
- else
- {
- *mask_on = 0;
- *mask_off = 0;
- return false;
- }
-}
-
-
-
-bool LLSelectMgr::selectGetPermissions(LLPermissions& result_perm)
-{
- bool first = true;
- LLPermissions perm;
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- if (!node->mValid)
- {
- return false;
- }
-
- if (first)
- {
- perm = *(node->mPermissions);
- first = false;
- }
- else
- {
- perm.accumulate(*(node->mPermissions));
- }
- }
-
- result_perm = perm;
-
- return true;
-}
-
-
-void LLSelectMgr::selectDelete()
-{
- S32 deleteable_count = 0;
-
- bool locked_but_deleteable_object = false;
- bool no_copy_but_deleteable_object = false;
- bool all_owned_by_you = true;
-
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++)
- {
- LLViewerObject* obj = (*iter)->getObject();
-
- if( obj->isAttachment() )
- {
- continue;
- }
-
- deleteable_count++;
-
- // Check to see if you can delete objects which are locked.
- if(!obj->permMove())
- {
- locked_but_deleteable_object = true;
- }
- if(!obj->permCopy())
- {
- no_copy_but_deleteable_object = true;
- }
- if(!obj->permYouOwner())
- {
- all_owned_by_you = false;
- }
- }
-
- if( 0 == deleteable_count )
- {
- make_ui_sound("UISndInvalidOp");
- return;
- }
-
- LLNotification::Params params("ConfirmObjectDeleteLock");
- params.functor.function(boost::bind(&LLSelectMgr::confirmDelete, _1, _2, getSelection()));
-
- if(locked_but_deleteable_object ||
- no_copy_but_deleteable_object ||
- !all_owned_by_you)
- {
- // convert any transient pie-menu selections to full selection so this operation
- // has some context
- // NOTE: if user cancels delete operation, this will potentially leave objects selected outside of build mode
- // but this is ok, if not ideal
- convertTransient();
-
- //This is messy, but needed to get all english our of the UI.
- if(locked_but_deleteable_object && !no_copy_but_deleteable_object && all_owned_by_you)
- {
- //Locked only
- params.name("ConfirmObjectDeleteLock");
- }
- else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you)
- {
- //No Copy only
- params.name("ConfirmObjectDeleteNoCopy");
- }
- else if(!locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you)
- {
- //not owned only
- params.name("ConfirmObjectDeleteNoOwn");
- }
- else if(locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you)
- {
- //locked and no copy
- params.name("ConfirmObjectDeleteLockNoCopy");
- }
- else if(locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you)
- {
- //locked and not owned
- params.name("ConfirmObjectDeleteLockNoOwn");
- }
- else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && !all_owned_by_you)
- {
- //no copy and not owned
- params.name("ConfirmObjectDeleteNoCopyNoOwn");
- }
- else
- {
- //locked, no copy and not owned
- params.name("ConfirmObjectDeleteLockNoCopyNoOwn");
- }
-
- LLNotifications::instance().add(params);
- }
- else
- {
- LLNotifications::instance().forceResponse(params, 0);
- }
-}
-
-// static
-bool LLSelectMgr::confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle)
-{
- S32 option = LLNotification::getSelectedOption(notification, response);
- if (!handle->getObjectCount())
- {
- LL_WARNS() << "Nothing to delete!" << LL_ENDL;
- return false;
- }
-
- switch(option)
- {
- case 0:
- {
- // TODO: Make sure you have delete permissions on all of them.
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- // attempt to derez into the trash.
- LLDeRezInfo info(DRD_TRASH, trash_id);
- LLSelectMgr::getInstance()->sendListToRegions("DeRezObject",
- packDeRezHeader,
- packObjectLocalID,
- logNoOp,
- (void*) &info,
- SEND_ONLY_ROOTS);
- // VEFFECT: Delete Object - one effect for all deletes
- if (LLSelectMgr::getInstance()->mSelectedObjects->mSelectType != SELECT_TYPE_HUD)
- {
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, true);
- effectp->setPositionGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal() );
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- F32 duration = 0.5f;
- duration += LLSelectMgr::getInstance()->mSelectedObjects->getObjectCount() / 64.f;
- effectp->setDuration(duration);
- }
-
- gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
-
- // Keep track of how many objects have been deleted.
- add(LLStatViewer::DELETE_OBJECT, LLSelectMgr::getInstance()->mSelectedObjects->getObjectCount());
- }
- break;
- case 1:
- default:
- break;
- }
- return false;
-}
-
-
-void LLSelectMgr::selectForceDelete()
-{
- sendListToRegions(
- "ObjectDelete",
- packDeleteHeader,
- packObjectLocalID,
- logNoOp,
- (void*)true,
- SEND_ONLY_ROOTS);
-}
-
-bool LLSelectMgr::selectGetEditMoveLinksetPermissions(bool &move, bool &modify)
-{
- move = true;
- modify = true;
- bool selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
-
- for (LLObjectSelection::iterator iter = getSelection()->begin();
- iter != getSelection()->end(); iter++)
- {
- LLSelectNode* nodep = *iter;
- LLViewerObject* object = nodep->getObject();
- if (!object || !nodep->mValid)
- {
- move = false;
- modify = false;
- return false;
- }
-
- LLViewerObject *root_object = object->getRootEdit();
- bool this_object_movable = false;
- if (object->permMove() && !object->isPermanentEnforced() &&
- ((root_object == NULL) || !root_object->isPermanentEnforced()) &&
- (object->permModify() || selecting_linked_set))
- {
- this_object_movable = true;
- }
- move = move && this_object_movable;
- modify = modify && object->permModify();
- }
-
- return true;
-}
-
-void LLSelectMgr::selectGetAggregateSaleInfo(U32 &num_for_sale,
- bool &is_for_sale_mixed,
- bool &is_sale_price_mixed,
- S32 &total_sale_price,
- S32 &individual_sale_price)
-{
- num_for_sale = 0;
- is_for_sale_mixed = false;
- is_sale_price_mixed = false;
- total_sale_price = 0;
- individual_sale_price = 0;
-
-
- // Empty set.
- if (getSelection()->root_begin() == getSelection()->root_end())
- return;
-
- LLSelectNode *node = *(getSelection()->root_begin());
- const bool first_node_for_sale = node->mSaleInfo.isForSale();
- const S32 first_node_sale_price = node->mSaleInfo.getSalePrice();
-
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- const bool node_for_sale = node->mSaleInfo.isForSale();
- const S32 node_sale_price = node->mSaleInfo.getSalePrice();
-
- // Set mixed if the fields don't match the first node's fields.
- if (node_for_sale != first_node_for_sale)
- is_for_sale_mixed = true;
- if (node_sale_price != first_node_sale_price)
- is_sale_price_mixed = true;
-
- if (node_for_sale)
- {
- total_sale_price += node_sale_price;
- num_for_sale ++;
- }
- }
-
- individual_sale_price = first_node_sale_price;
- if (is_for_sale_mixed)
- {
- is_sale_price_mixed = true;
- individual_sale_price = 0;
- }
-}
-
-// returns true if all nodes are valid. method also stores an
-// accumulated sale info.
-bool LLSelectMgr::selectGetSaleInfo(LLSaleInfo& result_sale_info)
-{
- bool first = true;
- LLSaleInfo sale_info;
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- if (!node->mValid)
- {
- return false;
- }
-
- if (first)
- {
- sale_info = node->mSaleInfo;
- first = false;
- }
- else
- {
- sale_info.accumulate(node->mSaleInfo);
- }
- }
-
- result_sale_info = sale_info;
-
- return true;
-}
-
-bool LLSelectMgr::selectGetAggregatePermissions(LLAggregatePermissions& result_perm)
-{
- bool first = true;
- LLAggregatePermissions perm;
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- if (!node->mValid)
- {
- return false;
- }
-
- if (first)
- {
- perm = node->mAggregatePerm;
- first = false;
- }
- else
- {
- perm.aggregate(node->mAggregatePerm);
- }
- }
-
- result_perm = perm;
-
- return true;
-}
-
-bool LLSelectMgr::selectGetAggregateTexturePermissions(LLAggregatePermissions& result_perm)
-{
- bool first = true;
- LLAggregatePermissions perm;
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- if (!node->mValid)
- {
- return false;
- }
-
- LLAggregatePermissions t_perm = node->getObject()->permYouOwner() ? node->mAggregateTexturePermOwner : node->mAggregateTexturePerm;
- if (first)
- {
- perm = t_perm;
- first = false;
- }
- else
- {
- perm.aggregate(t_perm);
- }
- }
-
- result_perm = perm;
-
- return true;
-}
-
-bool LLSelectMgr::isMovableAvatarSelected()
-{
- if (mAllowSelectAvatar && getSelection()->getObjectCount() == 1)
- {
- // nothing but avatar should be selected, so check that
- // there is only one selected object and it is a root
- LLViewerObject* obj = getSelection()->getFirstRootObject();
- return obj && obj->isAvatar() && getSelection()->getFirstMoveableNode(true);
- }
- return false;
-}
-
-//--------------------------------------------------------------------
-// Duplicate objects
-//--------------------------------------------------------------------
-
-// JC - If this doesn't work right, duplicate the selection list
-// before doing anything, do a deselect, then send the duplicate
-// messages.
-struct LLDuplicateData
-{
- LLVector3 offset;
- U32 flags;
-};
-
-void LLSelectMgr::selectDuplicate(const LLVector3& offset, bool select_copy)
-{
- if (mSelectedObjects->isAttachment())
- {
- //RN: do not duplicate attachments
- make_ui_sound("UISndInvalidOp");
- return;
- }
- if (!canDuplicate())
- {
- LLSelectNode* node = getSelection()->getFirstRootNode(NULL, true);
- if (node)
- {
- LLSD args;
- args["OBJ_NAME"] = node->mName;
- LLNotificationsUtil::add("NoCopyPermsNoObject", args);
- return;
- }
- }
- LLDuplicateData data;
-
- data.offset = offset;
- data.flags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0);
-
- sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS);
-
- if (select_copy)
- {
- // the new copy will be coming in selected
- deselectAll();
- }
- else
- {
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- node->mDuplicated = true;
- node->mDuplicatePos = node->getObject()->getPositionGlobal();
- node->mDuplicateRot = node->getObject()->getRotation();
- }
- }
-}
-
-void LLSelectMgr::repeatDuplicate()
-{
- if (mSelectedObjects->isAttachment())
- {
- //RN: do not duplicate attachments
- make_ui_sound("UISndInvalidOp");
- return;
- }
-
- std::vector<LLViewerObject*> non_duplicated_objects;
-
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- if (!node->mDuplicated)
- {
- non_duplicated_objects.push_back(node->getObject());
- }
- }
-
- // make sure only previously duplicated objects are selected
- for (std::vector<LLViewerObject*>::iterator iter = non_duplicated_objects.begin();
- iter != non_duplicated_objects.end(); ++iter)
- {
- LLViewerObject* objectp = *iter;
- deselectObjectAndFamily(objectp);
- }
-
- // duplicate objects in place
- LLDuplicateData data;
-
- data.offset = LLVector3::zero;
- data.flags = 0x0;
-
- sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS);
-
- // move current selection based on delta from duplication position and update duplication position
- for (LLObjectSelection::root_iterator iter = getSelection()->root_begin();
- iter != getSelection()->root_end(); iter++ )
- {
- LLSelectNode* node = *iter;
- if (node->mDuplicated)
- {
- LLQuaternion cur_rot = node->getObject()->getRotation();
- LLQuaternion rot_delta = (~node->mDuplicateRot * cur_rot);
- LLQuaternion new_rot = cur_rot * rot_delta;
- LLVector3d cur_pos = node->getObject()->getPositionGlobal();
- LLVector3d new_pos = cur_pos + ((cur_pos - node->mDuplicatePos) * rot_delta);
-
- node->mDuplicatePos = node->getObject()->getPositionGlobal();
- node->mDuplicateRot = node->getObject()->getRotation();
- node->getObject()->setPositionGlobal(new_pos);
- node->getObject()->setRotation(new_rot);
- }
- }
-
- sendMultipleUpdate(UPD_ROTATION | UPD_POSITION);
-}
-
-// static
-void LLSelectMgr::packDuplicate( LLSelectNode* node, void *duplicate_data )
-{
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID());
-}
-
-
-//--------------------------------------------------------------------
-// Duplicate On Ray
-//--------------------------------------------------------------------
-
-// Duplicates the selected objects, but places the copy along a cast
-// ray.
-struct LLDuplicateOnRayData
-{
- LLVector3 mRayStartRegion;
- LLVector3 mRayEndRegion;
- bool mBypassRaycast;
- bool mRayEndIsIntersection;
- LLUUID mRayTargetID;
- bool mCopyCenters;
- bool mCopyRotates;
- U32 mFlags;
-};
-
-void LLSelectMgr::selectDuplicateOnRay(const LLVector3 &ray_start_region,
- const LLVector3 &ray_end_region,
- bool bypass_raycast,
- bool ray_end_is_intersection,
- const LLUUID &ray_target_id,
- bool copy_centers,
- bool copy_rotates,
- bool select_copy)
-{
- if (mSelectedObjects->isAttachment())
- {
- // do not duplicate attachments
- make_ui_sound("UISndInvalidOp");
- return;
- }
-
- LLDuplicateOnRayData data;
-
- data.mRayStartRegion = ray_start_region;
- data.mRayEndRegion = ray_end_region;
- data.mBypassRaycast = bypass_raycast;
- data.mRayEndIsIntersection = ray_end_is_intersection;
- data.mRayTargetID = ray_target_id;
- data.mCopyCenters = copy_centers;
- data.mCopyRotates = copy_rotates;
- data.mFlags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0);
-
- sendListToRegions("ObjectDuplicateOnRay",
- packDuplicateOnRayHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS);
-
- if (select_copy)
- {
- // the new copy will be coming in selected
- deselectAll();
- }
-}
-
-// static
-void LLSelectMgr::packDuplicateOnRayHead(void *user_data)
-{
- LLMessageSystem *msg = gMessageSystem;
- LLDuplicateOnRayData *data = (LLDuplicateOnRayData *)user_data;
-
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() );
- msg->addVector3Fast(_PREHASH_RayStart, data->mRayStartRegion );
- msg->addVector3Fast(_PREHASH_RayEnd, data->mRayEndRegion );
- msg->addBOOLFast(_PREHASH_BypassRaycast, data->mBypassRaycast );
- msg->addBOOLFast(_PREHASH_RayEndIsIntersection, data->mRayEndIsIntersection );
- msg->addBOOLFast(_PREHASH_CopyCenters, data->mCopyCenters );
- msg->addBOOLFast(_PREHASH_CopyRotates, data->mCopyRotates );
- msg->addUUIDFast(_PREHASH_RayTargetID, data->mRayTargetID );
- msg->addU32Fast(_PREHASH_DuplicateFlags, data->mFlags );
-}
-
-
-
-//------------------------------------------------------------------------
-// Object position, scale, rotation update, all-in-one
-//------------------------------------------------------------------------
-
-void LLSelectMgr::sendMultipleUpdate(U32 type)
-{
- if (type == UPD_NONE) return;
- // send individual updates when selecting textures or individual objects
- ESendType send_type = (!gSavedSettings.getBOOL("EditLinkedParts") && !getTEMode()) ? SEND_ONLY_ROOTS : SEND_ROOTS_FIRST;
- if (send_type == SEND_ONLY_ROOTS)
- {
- // tell simulator to apply to whole linked sets
- type |= UPD_LINKED_SETS;
- }
-
- sendListToRegions(
- "MultipleObjectUpdate",
- packAgentAndSessionID,
- packMultipleUpdate,
- logNoOp,
- &type,
- send_type);
-}
-
-// static
-void LLSelectMgr::packMultipleUpdate(LLSelectNode* node, void *user_data)
-{
- LLViewerObject* object = node->getObject();
- U32 *type32 = (U32 *)user_data;
- U8 type = (U8)*type32;
- U8 data[256];
-
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
- gMessageSystem->addU8Fast(_PREHASH_Type, type );
-
- S32 offset = 0;
-
- // JC: You MUST pack the data in this order. The receiving
- // routine process_multiple_update_message on simulator will
- // extract them in this order.
-
- if (type & UPD_POSITION)
- {
- htolememcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12);
- offset += 12;
- }
- if (type & UPD_ROTATION)
- {
- LLQuaternion quat = object->getRotation();
- LLVector3 vec = quat.packToVector3();
- htolememcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12);
- offset += 12;
- }
- if (type & UPD_SCALE)
- {
- //LL_INFOS() << "Sending object scale " << object->getScale() << LL_ENDL;
- htolememcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12);
- offset += 12;
- }
- gMessageSystem->addBinaryDataFast(_PREHASH_Data, data, offset);
-}
-
-//------------------------------------------------------------------------
-// Ownership
-//------------------------------------------------------------------------
-struct LLOwnerData
-{
- LLUUID owner_id;
- LLUUID group_id;
- bool override;
-};
-
-void LLSelectMgr::sendOwner(const LLUUID& owner_id,
- const LLUUID& group_id,
- bool override)
-{
- LLOwnerData data;
-
- data.owner_id = owner_id;
- data.group_id = group_id;
- data.override = override;
-
- sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS);
-}
-
-// static
-void LLSelectMgr::packOwnerHead(void *user_data)
-{
- LLOwnerData *data = (LLOwnerData *)user_data;
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
- gMessageSystem->nextBlockFast(_PREHASH_HeaderData);
- gMessageSystem->addBOOLFast(_PREHASH_Override, data->override);
- gMessageSystem->addUUIDFast(_PREHASH_OwnerID, data->owner_id);
- gMessageSystem->addUUIDFast(_PREHASH_GroupID, data->group_id);
-}
-
-//------------------------------------------------------------------------
-// Group
-//------------------------------------------------------------------------
-
-void LLSelectMgr::sendGroup(const LLUUID& group_id)
-{
- LLUUID local_group_id(group_id);
- sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, logNoOp, &local_group_id, SEND_ONLY_ROOTS);
-}
-
-
-//------------------------------------------------------------------------
-// Buy
-//------------------------------------------------------------------------
-
-struct LLBuyData
-{
- std::vector<LLViewerObject*> mObjectsSent;
- LLUUID mCategoryID;
- LLSaleInfo mSaleInfo;
-};
-
-// *NOTE: does not work for multiple object buy, which UI does not
-// currently support sale info is used for verification only, if it
-// doesn't match region info then sale is canceled Need to get sale
-// info -as displayed in the UI- for every item.
-void LLSelectMgr::sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info)
-{
- LLBuyData buy;
- buy.mCategoryID = category_id;
- buy.mSaleInfo = sale_info;
- sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, logNoOp, &buy, SEND_ONLY_ROOTS);
-}
-
-// static
-void LLSelectMgr::packBuyObjectIDs(LLSelectNode* node, void* data)
-{
- LLBuyData* buy = (LLBuyData*)data;
-
- LLViewerObject* object = node->getObject();
- if (std::find(buy->mObjectsSent.begin(), buy->mObjectsSent.end(), object) == buy->mObjectsSent.end())
- {
- buy->mObjectsSent.push_back(object);
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
- gMessageSystem->addU8Fast(_PREHASH_SaleType, buy->mSaleInfo.getSaleType());
- gMessageSystem->addS32Fast(_PREHASH_SalePrice, buy->mSaleInfo.getSalePrice());
- }
-}
-
-//------------------------------------------------------------------------
-// Permissions
-//------------------------------------------------------------------------
-
-struct LLPermData
-{
- U8 mField;
- bool mSet;
- U32 mMask;
- bool mOverride;
-};
-
-// TODO: Make this able to fail elegantly.
-void LLSelectMgr::selectionSetObjectPermissions(U8 field,
- bool set,
- U32 mask,
- bool override)
-{
- LLPermData data;
-
- data.mField = field;
- data.mSet = set;
- data.mMask = mask;
- data.mOverride = override;
-
- sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, logNoOp, &data, SEND_ONLY_ROOTS);
-}
-
-void LLSelectMgr::packPermissionsHead(void* user_data)
-{
- LLPermData* data = (LLPermData*)user_data;
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_HeaderData);
- gMessageSystem->addBOOLFast(_PREHASH_Override, data->mOverride);
-}
-
-
-// Now that you've added a bunch of objects, send a select message
-// on the entire list for efficiency.
-/*
-void LLSelectMgr::sendSelect()
-{
- LL_ERRS() << "Not implemented" << LL_ENDL;
-}
-*/
-
-void LLSelectMgr::deselectAll()
-{
- if (!mSelectedObjects->getNumNodes())
- {
- return;
- }
-
- // Zap the angular velocity, as the sim will set it to zero
- for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
- iter != mSelectedObjects->end(); iter++ )
- {
- LLViewerObject *objectp = (*iter)->getObject();
- objectp->setAngularVelocity( 0,0,0 );
- objectp->setVelocity( 0,0,0 );
- }
-
- sendListToRegions(
- "ObjectDeselect",
- packAgentAndSessionID,
- packObjectLocalID,
- logNoOp,
- NULL,
- SEND_INDIVIDUALS);
-
- removeAll();
-
- mLastSentSelectionCenterGlobal.clearVec();
-
- updatePointAt();
-}
-
-void LLSelectMgr::deselectAllForStandingUp()
-{
- /*
- This function is similar deselectAll() except for the first if statement
- which was removed. This is needed as a workaround for DEV-2854
- */
-
- // Zap the angular velocity, as the sim will set it to zero
- for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
- iter != mSelectedObjects->end(); iter++ )
- {
- LLViewerObject *objectp = (*iter)->getObject();
- objectp->setAngularVelocity( 0,0,0 );
- objectp->setVelocity( 0,0,0 );
- }
-
- sendListToRegions(
- "ObjectDeselect",
- packAgentAndSessionID,
- packObjectLocalID,
- logNoOp,
- NULL,
- SEND_INDIVIDUALS);
-
- removeAll();
-
- mLastSentSelectionCenterGlobal.clearVec();
-
- updatePointAt();
-}
-
-void LLSelectMgr::deselectUnused()
-{
- // no more outstanding references to this selection
- if (mSelectedObjects->getNumRefs() == 1)
- {
- deselectAll();
- }
-}
-
-void LLSelectMgr::convertTransient()
-{
- LLObjectSelection::iterator node_it;
- for (node_it = mSelectedObjects->begin(); node_it != mSelectedObjects->end(); ++node_it)
- {
- LLSelectNode *nodep = *node_it;
- nodep->setTransient(false);
- }
-}
-
-void LLSelectMgr::deselectAllIfTooFar()
-{
- if (mSelectedObjects->isEmpty() || mSelectedObjects->mSelectType == SELECT_TYPE_HUD)
- {
- return;
- }
-
- // HACK: Don't deselect when we're navigating to rate an object's
- // owner or creator. JC
- if (gMenuObject->getVisible())
- {
- return;
- }
-
- LLVector3d selectionCenter = getSelectionCenterGlobal();
- if (gSavedSettings.getBOOL("LimitSelectDistance")
- && (!mSelectedObjects->getPrimaryObject() || !mSelectedObjects->getPrimaryObject()->isAvatar())
- && (mSelectedObjects->getPrimaryObject() != LLViewerMediaFocus::getInstance()->getFocusedObject())
- && !mSelectedObjects->isAttachment()
- && !selectionCenter.isExactlyZero())
- {
- F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance");
- F32 deselect_dist_sq = deselect_dist * deselect_dist;
-
- LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter;
- F32 select_dist_sq = (F32) select_delta.magVecSquared();
-
- if (select_dist_sq > deselect_dist_sq)
- {
- if (mDebugSelectMgr)
- {
- LL_INFOS() << "Selection manager: auto-deselecting, select_dist = " << (F32) sqrt(select_dist_sq) << LL_ENDL;
- LL_INFOS() << "agent pos global = " << gAgent.getPositionGlobal() << LL_ENDL;
- LL_INFOS() << "selection pos global = " << selectionCenter << LL_ENDL;
- }
-
- deselectAll();
- }
- }
-}
-
-
-void LLSelectMgr::selectionSetObjectName(const std::string& name)
-{
- std::string name_copy(name);
-
- // we only work correctly if 1 object is selected.
- if(mSelectedObjects->getRootObjectCount() == 1)
- {
- sendListToRegions("ObjectName",
- packAgentAndSessionID,
- packObjectName,
- logNoOp,
- (void*)(&name_copy),
- SEND_ONLY_ROOTS);
- }
- else if(mSelectedObjects->getObjectCount() == 1)
- {
- sendListToRegions("ObjectName",
- packAgentAndSessionID,
- packObjectName,
- logNoOp,
- (void*)(&name_copy),
- SEND_INDIVIDUALS);
- }
-}
-
-void LLSelectMgr::selectionSetObjectDescription(const std::string& desc)
-{
- std::string desc_copy(desc);
-
- // we only work correctly if 1 object is selected.
- if(mSelectedObjects->getRootObjectCount() == 1)
- {
- sendListToRegions("ObjectDescription",
- packAgentAndSessionID,
- packObjectDescription,
- logNoOp,
- (void*)(&desc_copy),
- SEND_ONLY_ROOTS);
- }
- else if(mSelectedObjects->getObjectCount() == 1)
- {
- sendListToRegions("ObjectDescription",
- packAgentAndSessionID,
- packObjectDescription,
- logNoOp,
- (void*)(&desc_copy),
- SEND_INDIVIDUALS);
- }
-}
-
-void LLSelectMgr::selectionSetObjectCategory(const LLCategory& category)
-{
- // for now, we only want to be able to set one root category at
- // a time.
- if(mSelectedObjects->getRootObjectCount() != 1) return;
- sendListToRegions("ObjectCategory",
- packAgentAndSessionID,
- packObjectCategory,
- logNoOp,
- (void*)(&category),
- SEND_ONLY_ROOTS);
-}
-
-void LLSelectMgr::selectionSetObjectSaleInfo(const LLSaleInfo& sale_info)
-{
- sendListToRegions("ObjectSaleInfo",
- packAgentAndSessionID,
- packObjectSaleInfo,
- logNoOp,
- (void*)(&sale_info),
- SEND_ONLY_ROOTS);
-}
-
-//----------------------------------------------------------------------
-// Attachments
-//----------------------------------------------------------------------
-
-void LLSelectMgr::sendAttach(U8 attachment_point, bool replace)
-{
- sendAttach(mSelectedObjects, attachment_point, replace);
-}
-
-void LLSelectMgr::sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace)
-{
- if (selection_handle.isNull())
- {
- return;
- }
-
- LLViewerObject* attach_object = selection_handle->getFirstRootObject();
-
- if (!attach_object || !isAgentAvatarValid() || selection_handle->mSelectType != SELECT_TYPE_WORLD)
- {
- return;
- }
-
- bool build_mode = LLToolMgr::getInstance()->inEdit();
- // Special case: Attach to default location for this object.
- if (0 == attachment_point ||
- get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)attachment_point, (LLViewerJointAttachment*)NULL))
- {
- if (!replace || attachment_point != 0)
- {
- // If we know the attachment point then we got here by clicking an
- // "Attach to..." context menu item, so we should add, not replace.
- attachment_point |= ATTACHMENT_ADD;
- }
-
- sendListToRegions(
- selection_handle,
- "ObjectAttach",
- packAgentIDAndSessionAndAttachment,
- packObjectIDAndRotation,
- logAttachmentRequest,
- &attachment_point,
- SEND_ONLY_ROOTS );
- if (!build_mode)
- {
- // After "ObjectAttach" server will unsubscribe us from properties updates
- // so either deselect objects or resend selection after attach packet reaches server
- // In case of build_mode LLPanelObjectInventory::refresh() will deal with selection
- // Still unsubscribe even in case selection_handle is not current selection
- deselectAll();
- }
- }
-}
-
-void LLSelectMgr::sendDetach()
-{
- if (!mSelectedObjects->getNumNodes() || mSelectedObjects->mSelectType == SELECT_TYPE_WORLD)
- {
- return;
- }
-
- sendListToRegions(
- "ObjectDetach",
- packAgentAndSessionID,
- packObjectLocalID,
- logDetachRequest,
- NULL,
- SEND_ONLY_ROOTS );
-}
-
-
-void LLSelectMgr::sendDropAttachment()
-{
- if (!mSelectedObjects->getNumNodes() || mSelectedObjects->mSelectType == SELECT_TYPE_WORLD)
- {
- return;
- }
-
- sendListToRegions(
- "ObjectDrop",
- packAgentAndSessionID,
- packObjectLocalID,
- logDetachRequest,
- NULL,
- SEND_ONLY_ROOTS);
-}
-
-//----------------------------------------------------------------------
-// Links
-//----------------------------------------------------------------------
-
-void LLSelectMgr::sendLink()
-{
- if (!mSelectedObjects->getNumNodes())
- {
- return;
- }
-
- sendListToRegions(
- "ObjectLink",
- packAgentAndSessionID,
- packObjectLocalID,
- logNoOp,
- NULL,
- SEND_ONLY_ROOTS);
-}
-
-void LLSelectMgr::sendDelink()
-{
- if (!mSelectedObjects->getNumNodes())
- {
- return;
- }
-
- struct f : public LLSelectedObjectFunctor
- { //on delink, any modifyable object should
- f() {}
-
- virtual bool apply(LLViewerObject* object)
- {
- if (object->permModify())
- {
- if (object->getPhysicsShapeType() == LLViewerObject::PHYSICS_SHAPE_NONE)
- {
- object->setPhysicsShapeType(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
- object->updateFlags();
- }
- }
- return true;
- }
- } sendfunc;
- getSelection()->applyToObjects(&sendfunc);
-
-
- // Delink needs to send individuals so you can unlink a single object from
- // a linked set.
- sendListToRegions(
- "ObjectDelink",
- packAgentAndSessionID,
- packObjectLocalID,
- logNoOp,
- NULL,
- SEND_INDIVIDUALS);
-}
-
-
-//----------------------------------------------------------------------
-// Hinges
-//----------------------------------------------------------------------
-
-/*
-void LLSelectMgr::sendHinge(U8 type)
-{
- if (!mSelectedObjects->getNumNodes())
- {
- return;
- }
-
- sendListToRegions(
- "ObjectHinge",
- packHingeHead,
- packObjectLocalID,
- &type,
- SEND_ONLY_ROOTS);
-}
-
-
-void LLSelectMgr::sendDehinge()
-{
- if (!mSelectedObjects->getNumNodes())
- {
- return;
- }
-
- sendListToRegions(
- "ObjectDehinge",
- packAgentAndSessionID,
- packObjectLocalID,
- NULL,
- SEND_ONLY_ROOTS);
-}*/
-
-void LLSelectMgr::sendSelect()
-{
- if (!mSelectedObjects->getNumNodes())
- {
- return;
- }
-
- sendListToRegions(
- "ObjectSelect",
- packAgentAndSessionID,
- packObjectLocalID,
- logNoOp,
- NULL,
- SEND_INDIVIDUALS);
-}
-
-// static
-void LLSelectMgr::packHingeHead(void *user_data)
-{
- U8 *type = (U8 *)user_data;
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
- gMessageSystem->nextBlockFast(_PREHASH_JointType);
- gMessageSystem->addU8Fast(_PREHASH_Type, *type );
-}
-
-
-void LLSelectMgr::selectionDump()
-{
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- object->dump();
- return true;
- }
- } func;
- getSelection()->applyToObjects(&func);
-}
-
-void LLSelectMgr::saveSelectedObjectColors()
-{
- struct f : public LLSelectedNodeFunctor
- {
- virtual bool apply(LLSelectNode* node)
- {
- node->saveColors();
- return true;
- }
- } func;
- getSelection()->applyToNodes(&func);
-}
-
-void LLSelectMgr::saveSelectedShinyColors()
-{
- struct f : public LLSelectedNodeFunctor
- {
- virtual bool apply(LLSelectNode* node)
- {
- node->saveShinyColors();
- return true;
- }
- } func;
- getSelection()->applyToNodes(&func);
-}
-
-void LLSelectMgr::saveSelectedObjectTextures()
-{
- // invalidate current selection so we update saved textures
- struct f : public LLSelectedNodeFunctor
- {
- virtual bool apply(LLSelectNode* node)
- {
- node->mValid = false;
- return true;
- }
- } func;
- getSelection()->applyToNodes(&func);
-
- // request object properties message to get updated permissions data
- sendSelect();
-}
-
-
-// This routine should be called whenever a drag is initiated.
-// also need to know to which simulator to send update message
-void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type)
-{
- if (mSelectedObjects->isEmpty())
- {
- // nothing selected, so nothing to save
- return;
- }
-
- struct f : public LLSelectedNodeFunctor
- {
- EActionType mActionType;
- LLSelectMgr* mManager;
- f(EActionType a, LLSelectMgr* p) : mActionType(a), mManager(p) {}
- virtual bool apply(LLSelectNode* selectNode)
- {
- LLViewerObject* object = selectNode->getObject();
- if (!object)
- {
- return true; // skip
- }
- selectNode->mSavedPositionLocal = object->getPosition();
- if (object->isAttachment())
- {
- if (object->isRootEdit())
- {
- LLXform* parent_xform = object->mDrawable->getXform()->getParent();
- if (parent_xform)
- {
- selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition());
- }
- else
- {
- selectNode->mSavedPositionGlobal = object->getPositionGlobal();
- }
- }
- else
- {
- LLViewerObject* attachment_root = (LLViewerObject*)object->getParent();
- LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL;
- if (parent_xform)
- {
- LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
- LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation());
- selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos);
- }
- else
- {
- selectNode->mSavedPositionGlobal = object->getPositionGlobal();
- }
- }
- selectNode->mSavedRotation = object->getRenderRotation();
- }
- else
- {
- selectNode->mSavedPositionGlobal = object->getPositionGlobal();
- selectNode->mSavedRotation = object->getRotationRegion();
- }
-
- selectNode->mSavedScale = object->getScale();
- selectNode->saveTextureScaleRatios(mManager->mTextureChannel);
- return true;
- }
- } func(action_type, this);
- getSelection()->applyToNodes(&func);
-
- mSavedSelectionBBox = getBBoxOfSelection();
-}
-
-struct LLSelectMgrApplyFlags : public LLSelectedObjectFunctor
-{
- LLSelectMgrApplyFlags(U32 flags, bool state) : mFlags(flags), mState(state) {}
- U32 mFlags;
- bool mState;
- virtual bool apply(LLViewerObject* object)
- {
- if ( object->permModify())
- {
- if (object->isRoot()) // don't send for child objects
- {
- object->setFlags( mFlags, mState);
- }
- else if (FLAGS_WORLD & mFlags && ((LLViewerObject*)object->getRoot())->isSelected())
- {
- // FLAGS_WORLD are shared by all items in linkset
- object->setFlagsWithoutUpdate(FLAGS_WORLD & mFlags, mState);
- }
- };
- return true;
- }
-};
-
-void LLSelectMgr::selectionUpdatePhysics(bool physics)
-{
- LLSelectMgrApplyFlags func( FLAGS_USE_PHYSICS, physics);
- getSelection()->applyToObjects(&func);
-}
-
-void LLSelectMgr::selectionUpdateTemporary(bool is_temporary)
-{
- LLSelectMgrApplyFlags func( FLAGS_TEMPORARY_ON_REZ, is_temporary);
- getSelection()->applyToObjects(&func);
-}
-
-void LLSelectMgr::selectionUpdatePhantom(bool is_phantom)
-{
- LLSelectMgrApplyFlags func( FLAGS_PHANTOM, is_phantom);
- getSelection()->applyToObjects(&func);
-}
-
-//----------------------------------------------------------------------
-// Helpful packing functions for sendObjectMessage()
-//----------------------------------------------------------------------
-
-// static
-void LLSelectMgr::packAgentIDAndSessionAndAttachment( void *user_data)
-{
- U8 *attachment_point = (U8*)user_data;
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addU8Fast(_PREHASH_AttachmentPoint, *attachment_point);
-}
-
-// static
-void LLSelectMgr::packAgentID( void *user_data)
-{
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
-}
-
-// static
-void LLSelectMgr::packAgentAndSessionID(void* user_data)
-{
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-}
-
-// static
-void LLSelectMgr::packAgentAndGroupID(void* user_data)
-{
- LLOwnerData *data = (LLOwnerData *)user_data;
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, data->owner_id );
- gMessageSystem->addUUIDFast(_PREHASH_GroupID, data->group_id );
-}
-
-// static
-void LLSelectMgr::packAgentAndSessionAndGroupID(void* user_data)
-{
- LLUUID* group_idp = (LLUUID*) user_data;
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addUUIDFast(_PREHASH_GroupID, *group_idp);
-}
-
-// static
-void LLSelectMgr::packDuplicateHeader(void* data)
-{
- LLUUID group_id(gAgent.getGroupID());
- packAgentAndSessionAndGroupID(&group_id);
-
- LLDuplicateData* dup_data = (LLDuplicateData*) data;
-
- gMessageSystem->nextBlockFast(_PREHASH_SharedData);
- gMessageSystem->addVector3Fast(_PREHASH_Offset, dup_data->offset);
- gMessageSystem->addU32Fast(_PREHASH_DuplicateFlags, dup_data->flags);
-}
-
-// static
-void LLSelectMgr::packDeleteHeader(void* userdata)
-{
- bool force = (bool)(intptr_t)userdata;
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addBOOLFast(_PREHASH_Force, force);
-}
-
-// static
-void LLSelectMgr::packAgentGroupAndCatID(void* user_data)
-{
- LLBuyData* buy = (LLBuyData*)user_data;
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
- gMessageSystem->addUUIDFast(_PREHASH_CategoryID, buy->mCategoryID);
-}
-
-//static
-void LLSelectMgr::packDeRezHeader(void* user_data)
-{
- LLDeRezInfo* info = (LLDeRezInfo*)user_data;
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_AgentBlock);
- gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
- gMessageSystem->addU8Fast(_PREHASH_Destination, (U8)info->mDestination);
- gMessageSystem->addUUIDFast(_PREHASH_DestinationID, info->mDestinationID);
- LLUUID tid;
- tid.generate();
- gMessageSystem->addUUIDFast(_PREHASH_TransactionID, tid);
- const U8 PACKET = 1;
- gMessageSystem->addU8Fast(_PREHASH_PacketCount, PACKET);
- gMessageSystem->addU8Fast(_PREHASH_PacketNumber, PACKET);
-}
-
-// static
-void LLSelectMgr::packObjectID(LLSelectNode* node, void *user_data)
-{
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addUUIDFast(_PREHASH_ObjectID, node->getObject()->mID );
-}
-
-void LLSelectMgr::packObjectIDAndRotation(LLSelectNode* node, void *user_data)
-{
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() );
- gMessageSystem->addQuatFast(_PREHASH_Rotation, node->getObject()->getRotation());
-}
-
-void LLSelectMgr::packObjectClickAction(LLSelectNode* node, void *user_data)
-{
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() );
- gMessageSystem->addU8("ClickAction", node->getObject()->getClickAction());
-}
-
-void LLSelectMgr::packObjectIncludeInSearch(LLSelectNode* node, void *user_data)
-{
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() );
- gMessageSystem->addBOOL("IncludeInSearch", node->getObject()->getIncludeInSearch());
-}
-
-// static
-void LLSelectMgr::packObjectLocalID(LLSelectNode* node, void *)
-{
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID());
-}
-
-// static
-void LLSelectMgr::packObjectName(LLSelectNode* node, void* user_data)
-{
- const std::string* name = (const std::string*)user_data;
- if(!name->empty())
- {
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
- gMessageSystem->addStringFast(_PREHASH_Name, *name);
- }
-}
-
-// static
-void LLSelectMgr::packObjectDescription(LLSelectNode* node, void* user_data)
-{
- const std::string* desc = (const std::string*)user_data;
- if(desc)
- { // Empty (non-null, but zero length) descriptions are OK
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
- gMessageSystem->addStringFast(_PREHASH_Description, *desc);
- }
-}
-
-// static
-void LLSelectMgr::packObjectCategory(LLSelectNode* node, void* user_data)
-{
- LLCategory* category = (LLCategory*)user_data;
- if(!category) return;
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
- category->packMessage(gMessageSystem);
-}
-
-// static
-void LLSelectMgr::packObjectSaleInfo(LLSelectNode* node, void* user_data)
-{
- LLSaleInfo* sale_info = (LLSaleInfo*)user_data;
- if(!sale_info) return;
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
- sale_info->packMessage(gMessageSystem);
-}
-
-// static
-void LLSelectMgr::packPhysics(LLSelectNode* node, void *user_data)
-{
-}
-
-// static
-void LLSelectMgr::packShape(LLSelectNode* node, void *user_data)
-{
-}
-
-// static
-void LLSelectMgr::packPermissions(LLSelectNode* node, void *user_data)
-{
- LLPermData *data = (LLPermData *)user_data;
-
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID());
-
- gMessageSystem->addU8Fast(_PREHASH_Field, data->mField);
- gMessageSystem->addBOOLFast(_PREHASH_Set, data->mSet);
- gMessageSystem->addU32Fast(_PREHASH_Mask, data->mMask);
-}
-
-// Utility function to send some information to every region containing
-// an object on the selection list. We want to do this to reduce the total
-// number of packets sent by the viewer.
-void LLSelectMgr::sendListToRegions(const std::string& message_name,
- void (*pack_header)(void *user_data),
- void (*pack_body)(LLSelectNode* node, void *user_data),
- void (*log_func)(LLSelectNode* node, void *user_data),
- void *user_data,
- ESendType send_type)
-{
- sendListToRegions(mSelectedObjects, message_name, pack_header, pack_body, log_func, user_data, send_type);
-}
-void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle,
- const std::string& message_name,
- void (*pack_header)(void *user_data),
- void (*pack_body)(LLSelectNode* node, void *user_data),
- void (*log_func)(LLSelectNode* node, void *user_data),
- void *user_data,
- ESendType send_type)
-{
- LLSelectNode* node;
- LLSelectNode* linkset_root = NULL;
- LLViewerRegion* last_region;
- LLViewerRegion* current_region;
- S32 objects_in_this_packet = 0;
-
- bool link_operation = message_name == "ObjectLink";
-
- if (mAllowSelectAvatar)
- {
- if (selected_handle->getObjectCount() == 1
- && selected_handle->getFirstObject() != NULL
- && selected_handle->getFirstObject()->isAvatar())
- {
- // Server doesn't move avatars at the moment, it is a local debug feature,
- // but server does update position regularly, so do not drop mLastPositionLocal
- // Position override for avatar gets reset in LLAgentCamera::resetView().
- }
- else
- {
- // drop mLastPositionLocal (allow next update through)
- resetObjectOverrides(selected_handle);
- }
- }
- else
- {
- //clear update override data (allow next update through)
- resetObjectOverrides(selected_handle);
- }
-
- std::queue<LLSelectNode*> nodes_to_send;
-
- struct push_all : public LLSelectedNodeFunctor
- {
- std::queue<LLSelectNode*>& nodes_to_send;
- push_all(std::queue<LLSelectNode*>& n) : nodes_to_send(n) {}
- virtual bool apply(LLSelectNode* node)
- {
- if (node->getObject())
- {
- nodes_to_send.push(node);
- }
- return true;
- }
- };
- struct push_some : public LLSelectedNodeFunctor
- {
- std::queue<LLSelectNode*>& nodes_to_send;
- bool mRoots;
- push_some(std::queue<LLSelectNode*>& n, bool roots) : nodes_to_send(n), mRoots(roots) {}
- virtual bool apply(LLSelectNode* node)
- {
- if (node->getObject())
- {
- bool is_root = node->getObject()->isRootEdit();
- if ((mRoots && is_root) || (!mRoots && !is_root))
- {
- nodes_to_send.push(node);
- }
- }
- return true;
- }
- };
- struct push_all pushall(nodes_to_send);
- struct push_some pushroots(nodes_to_send, true);
- struct push_some pushnonroots(nodes_to_send, false);
-
- switch(send_type)
- {
- case SEND_ONLY_ROOTS:
- if(message_name == "ObjectBuy")
- selected_handle->applyToRootNodes(&pushroots);
- else
- selected_handle->applyToRootNodes(&pushall);
-
- break;
- case SEND_INDIVIDUALS:
- selected_handle->applyToNodes(&pushall);
- break;
- case SEND_ROOTS_FIRST:
- // first roots...
- selected_handle->applyToNodes(&pushroots);
- // then children...
- selected_handle->applyToNodes(&pushnonroots);
- break;
- case SEND_CHILDREN_FIRST:
- // first children...
- selected_handle->applyToNodes(&pushnonroots);
- // then roots...
- selected_handle->applyToNodes(&pushroots);
- break;
-
- default:
- LL_ERRS() << "Bad send type " << send_type << " passed to SendListToRegions()" << LL_ENDL;
- }
-
- // bail if nothing selected
- if (nodes_to_send.empty())
- {
- return;
- }
-
- node = nodes_to_send.front();
- nodes_to_send.pop();
-
- // cache last region information
- current_region = node->getObject()->getRegion();
-
- // Start duplicate message
- // CRO: this isn't
- gMessageSystem->newMessage(message_name.c_str());
- (*pack_header)(user_data);
-
- // For each object
- while (node != NULL)
- {
- // remember the last region, look up the current one
- last_region = current_region;
- current_region = node->getObject()->getRegion();
-
- // if to same simulator and message not too big
- if ((current_region == last_region)
- && (! gMessageSystem->isSendFull(NULL))
- && (objects_in_this_packet < MAX_OBJECTS_PER_PACKET))
- {
- if (link_operation && linkset_root == NULL)
- {
- // linksets over 254 will be split into multiple messages,
- // but we need to provide same root for all messages or we will get separate linksets
- linkset_root = node;
- }
- // add another instance of the body of the data
- (*pack_body)(node, user_data);
- // do any related logging
- (*log_func)(node, user_data);
- ++objects_in_this_packet;
-
- // and on to the next object
- if(nodes_to_send.empty())
- {
- node = NULL;
- }
- else
- {
- node = nodes_to_send.front();
- nodes_to_send.pop();
- }
- }
- else
- {
- // otherwise send current message and start new one
- gMessageSystem->sendReliable( last_region->getHost());
- objects_in_this_packet = 0;
-
- gMessageSystem->newMessage(message_name.c_str());
- (*pack_header)(user_data);
-
- if (linkset_root != NULL)
- {
- if (current_region != last_region)
- {
- // root should be in one region with the child, reset it
- linkset_root = NULL;
- }
- else
- {
- // add root instance into new message
- (*pack_body)(linkset_root, user_data);
- ++objects_in_this_packet;
- }
- }
-
- // don't move to the next object, we still need to add the
- // body data.
- }
- }
-
- // flush messages
- if (gMessageSystem->getCurrentSendTotal() > 0)
- {
- gMessageSystem->sendReliable( current_region->getHost());
- }
- else
- {
- gMessageSystem->clearMessage();
- }
-
- // LL_INFOS() << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << LL_ENDL;
-}
-
-
-//
-// Network communications
-//
-
-void LLSelectMgr::requestObjectPropertiesFamily(LLViewerObject* object)
-{
- LLMessageSystem* msg = gMessageSystem;
-
- msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_RequestFlags, 0x0 );
- msg->addUUIDFast(_PREHASH_ObjectID, object->mID );
-
- LLViewerRegion* regionp = object->getRegion();
- msg->sendReliable( regionp->getHost() );
-}
-
-
-// static
-void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data)
-{
- S32 i;
- S32 count = msg->getNumberOfBlocksFast(_PREHASH_ObjectData);
- for (i = 0; i < count; i++)
- {
- LLUUID id;
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, id, i);
-
- LLUUID creator_id;
- LLUUID owner_id;
- LLUUID group_id;
- LLUUID last_owner_id;
- U64 creation_date;
- LLUUID extra_id;
- U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask;
- LLSaleInfo sale_info;
- LLCategory category;
- LLAggregatePermissions ag_perms;
- LLAggregatePermissions ag_texture_perms;
- LLAggregatePermissions ag_texture_perms_owner;
-
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_CreatorID, creator_id, i);
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, i);
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id, i);
- msg->getU64Fast(_PREHASH_ObjectData, _PREHASH_CreationDate, creation_date, i);
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, base_mask, i);
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, owner_mask, i);
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_GroupMask, group_mask, i);
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, everyone_mask, i);
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, next_owner_mask, i);
- sale_info.unpackMultiMessage(msg, _PREHASH_ObjectData, i);
-
- ag_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePerms, i);
- ag_texture_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTextures, i);
- ag_texture_perms_owner.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTexturesOwner, i);
- category.unpackMultiMessage(msg, _PREHASH_ObjectData, i);
-
- S16 inv_serial = 0;
- msg->getS16Fast(_PREHASH_ObjectData, _PREHASH_InventorySerial, inv_serial, i);
-
- LLUUID item_id;
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ItemID, item_id, i);
- LLUUID folder_id;
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FolderID, folder_id, i);
- LLUUID from_task_id;
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FromTaskID, from_task_id, i);
-
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, last_owner_id, i);
-
- std::string name;
- msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, name, i);
- std::string desc;
- msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, desc, i);
-
- std::string touch_name;
- msg->getStringFast(_PREHASH_ObjectData, _PREHASH_TouchName, touch_name, i);
- std::string sit_name;
- msg->getStringFast(_PREHASH_ObjectData, _PREHASH_SitName, sit_name, i);
-
- //unpack TE IDs
- uuid_vec_t texture_ids;
- S32 size = msg->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_TextureID);
- if (size > 0)
- {
- S8 packed_buffer[SELECT_MAX_TES * UUID_BYTES];
- msg->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureID, packed_buffer, 0, i, SELECT_MAX_TES * UUID_BYTES);
-
- for (S32 buf_offset = 0; buf_offset < size; buf_offset += UUID_BYTES)
- {
- LLUUID tid;
- memcpy(tid.mData, packed_buffer + buf_offset, UUID_BYTES); /* Flawfinder: ignore */
- texture_ids.push_back(tid);
- }
- }
-
-
- // Iterate through nodes at end, since it can be on both the regular AND hover list
- struct f : public LLSelectedNodeFunctor
- {
- LLUUID mID;
- f(const LLUUID& id) : mID(id) {}
- virtual bool apply(LLSelectNode* node)
- {
- return (node->getObject() && node->getObject()->mID == mID);
- }
- } func(id);
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func);
-
- if (!node)
- {
- LL_WARNS() << "Couldn't find object " << id << " selected." << LL_ENDL;
- }
- else
- {
- // save texture data as soon as we get texture perms first time
- bool save_textures = !node->mValid;
- if (node->mInventorySerial != inv_serial && node->getObject())
- {
- node->getObject()->dirtyInventory();
-
- // Even if this isn't object's first udpate, inventory changed
- // and some of the applied textures might have been in inventory
- // so update texture list.
- save_textures = true;
- }
-
- if (save_textures)
- {
- bool can_copy = false;
- bool can_transfer = false;
-
- LLAggregatePermissions::EValue value = LLAggregatePermissions::AP_NONE;
- if(node->getObject()->permYouOwner())
- {
- value = ag_texture_perms_owner.getValue(PERM_COPY);
- if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
- {
- can_copy = true;
- }
- value = ag_texture_perms_owner.getValue(PERM_TRANSFER);
- if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
- {
- can_transfer = true;
- }
- }
- else
- {
- value = ag_texture_perms.getValue(PERM_COPY);
- if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
- {
- can_copy = true;
- }
- value = ag_texture_perms.getValue(PERM_TRANSFER);
- if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
- {
- can_transfer = true;
- }
- }
-
- if (can_copy && can_transfer)
- {
- node->saveTextures(texture_ids);
- }
-
- if (can_copy && can_transfer && node->getObject()->getVolume())
- {
- uuid_vec_t material_ids;
- gltf_materials_vec_t override_materials;
- LLVOVolume* vobjp = (LLVOVolume*)node->getObject();
- for (int i = 0; i < vobjp->getNumTEs(); ++i)
- {
- material_ids.push_back(vobjp->getRenderMaterialID(i));
-
- // Make a copy to ensure we won't affect live material
- // with any potential changes nor live changes will be
- // reflected in a saved copy.
- // Like changes from local material (reuses pointer) or
- // from live editor (revert mechanics might modify this)
- LLGLTFMaterial* old_override = node->getObject()->getTE(i)->getGLTFMaterialOverride();
- if (old_override)
- {
- LLPointer<LLGLTFMaterial> mat = new LLGLTFMaterial(*old_override);
- override_materials.push_back(mat);
- }
- else
- {
- override_materials.push_back(nullptr);
- }
- }
- // processObjectProperties does not include overrides so this
- // might need to be moved to LLGLTFMaterialOverrideDispatchHandler
- node->saveGLTFMaterials(material_ids, override_materials);
- }
- }
-
- node->mValid = true;
- node->mPermissions->init(creator_id, owner_id,
- last_owner_id, group_id);
- node->mPermissions->initMasks(base_mask, owner_mask, everyone_mask, group_mask, next_owner_mask);
- node->mCreationDate = creation_date;
- node->mItemID = item_id;
- node->mFolderID = folder_id;
- node->mFromTaskID = from_task_id;
- node->mName.assign(name);
- node->mDescription.assign(desc);
- node->mSaleInfo = sale_info;
- node->mAggregatePerm = ag_perms;
- node->mAggregateTexturePerm = ag_texture_perms;
- node->mAggregateTexturePermOwner = ag_texture_perms_owner;
- node->mCategory = category;
- node->mInventorySerial = inv_serial;
- node->mSitName.assign(sit_name);
- node->mTouchName.assign(touch_name);
- }
- }
-
- dialog_refresh_all();
-
- // hack for left-click buy object
- LLToolPie::selectionPropertiesReceived();
-}
-
-// static
-void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** user_data)
-{
- LLUUID id;
-
- U32 request_flags;
- LLUUID creator_id;
- LLUUID owner_id;
- LLUUID group_id;
- LLUUID extra_id;
- U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask;
- LLSaleInfo sale_info;
- LLCategory category;
-
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_RequestFlags, request_flags );
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, id );
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id );
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id );
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, base_mask );
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, owner_mask );
- msg->getU32Fast(_PREHASH_ObjectData,_PREHASH_GroupMask, group_mask );
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, everyone_mask );
- msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, next_owner_mask);
- sale_info.unpackMessage(msg, _PREHASH_ObjectData);
- category.unpackMessage(msg, _PREHASH_ObjectData);
-
- LLUUID last_owner_id;
- msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, last_owner_id );
-
- // unpack name & desc
- std::string name;
- msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, name);
-
- std::string desc;
- msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, desc);
-
- // the reporter widget askes the server for info about picked objects
- if (request_flags & COMPLAINT_REPORT_REQUEST )
- {
- LLFloaterReporter *reporterp = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");
- if (reporterp)
- {
- LLAvatarName av_name;
- LLAvatarNameCache::get(owner_id, &av_name);
- reporterp->setPickedObjectProperties(name, av_name.getUserName(), owner_id);
- }
- }
- else if (request_flags & OBJECT_PAY_REQUEST)
- {
- // check if the owner of the paid object is muted
- LLMuteList::getInstance()->autoRemove(owner_id, LLMuteList::AR_MONEY);
- }
-
- // Now look through all of the hovered nodes
- struct f : public LLSelectedNodeFunctor
- {
- LLUUID mID;
- f(const LLUUID& id) : mID(id) {}
- virtual bool apply(LLSelectNode* node)
- {
- return (node->getObject() && node->getObject()->mID == mID);
- }
- } func(id);
- LLSelectNode* node = LLSelectMgr::getInstance()->mHoverObjects->getFirstNode(&func);
-
- if (node)
- {
- node->mValid = true;
- node->mPermissions->init(LLUUID::null, owner_id,
- last_owner_id, group_id);
- node->mPermissions->initMasks(base_mask, owner_mask, everyone_mask, group_mask, next_owner_mask);
- node->mSaleInfo = sale_info;
- node->mCategory = category;
- node->mName.assign(name);
- node->mDescription.assign(desc);
- }
-
- dialog_refresh_all();
-}
-
-
-// static
-void LLSelectMgr::processForceObjectSelect(LLMessageSystem* msg, void**)
-{
- bool reset_list;
- msg->getBOOL("Header", "ResetList", reset_list);
-
- if (reset_list)
- {
- LLSelectMgr::getInstance()->deselectAll();
- }
-
- LLUUID full_id;
- S32 local_id;
- LLViewerObject* object;
- std::vector<LLViewerObject*> objects;
- S32 i;
- S32 block_count = msg->getNumberOfBlocks("Data");
-
- for (i = 0; i < block_count; i++)
- {
- msg->getS32("Data", "LocalID", local_id, i);
-
- gObjectList.getUUIDFromLocal(full_id,
- local_id,
- msg->getSenderIP(),
- msg->getSenderPort());
- object = gObjectList.findObject(full_id);
- if (object)
- {
- objects.push_back(object);
- }
- }
-
- // Don't select, just highlight
- LLSelectMgr::getInstance()->highlightObjectAndFamily(objects);
-}
-
-extern F32 gGLModelView[16];
-
-void LLSelectMgr::updateSilhouettes()
-{
- S32 num_sils_genned = 0;
-
- LLVector3d cameraPos = gAgentCamera.getCameraPositionGlobal();
- F32 currentCameraZoom = gAgentCamera.getCurrentCameraBuildOffset();
-
- if (!mSilhouetteImagep)
- {
- mSilhouetteImagep = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", FTT_LOCAL_FILE, true, LLGLTexture::BOOST_UI);
- }
-
- mHighlightedObjects->cleanupNodes();
-
- if((cameraPos - mLastCameraPos).magVecSquared() > SILHOUETTE_UPDATE_THRESHOLD_SQUARED * currentCameraZoom * currentCameraZoom)
- {
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- object->setChanged(LLXform::SILHOUETTE);
- return true;
- }
- } func;
- getSelection()->applyToObjects(&func);
-
- mLastCameraPos = gAgentCamera.getCameraPositionGlobal();
- }
-
- std::vector<LLViewerObject*> changed_objects;
-
- updateSelectionSilhouette(mSelectedObjects, num_sils_genned, changed_objects);
- if (mRectSelectedObjects.size() > 0)
- {
- //gGLSPipelineSelection.set();
-
- //mSilhouetteImagep->bindTexture();
- //glAlphaFunc(GL_GREATER, sHighlightAlphaTest);
-
- std::set<LLViewerObject*> roots;
-
- // sync mHighlightedObjects with mRectSelectedObjects since the latter is rebuilt every frame and former
- // persists from frame to frame to avoid regenerating object silhouettes
- // mHighlightedObjects includes all siblings of rect selected objects
-
- bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
-
- // generate list of roots from current object selection
- for (std::set<LLPointer<LLViewerObject> >::iterator iter = mRectSelectedObjects.begin();
- iter != mRectSelectedObjects.end(); iter++)
- {
- LLViewerObject *objectp = *iter;
- if (select_linked_set)
- {
- LLViewerObject *rootp = (LLViewerObject*)objectp->getRoot();
- roots.insert(rootp);
- }
- else
- {
- roots.insert(objectp);
- }
- }
-
- // remove highlight nodes not in roots list
- std::vector<LLSelectNode*> remove_these_nodes;
- std::vector<LLViewerObject*> remove_these_roots;
-
- for (LLObjectSelection::iterator iter = mHighlightedObjects->begin();
- iter != mHighlightedObjects->end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* objectp = node->getObject();
- if (!objectp)
- continue;
- if (objectp->isRoot() || !select_linked_set)
- {
- if (roots.count(objectp) == 0)
- {
- remove_these_nodes.push_back(node);
- }
- else
- {
- remove_these_roots.push_back(objectp);
- }
- }
- else
- {
- LLViewerObject* rootp = (LLViewerObject*)objectp->getRoot();
-
- if (roots.count(rootp) == 0)
- {
- remove_these_nodes.push_back(node);
- }
- }
- }
-
- // remove all highlight nodes no longer in rectangle selection
- for (std::vector<LLSelectNode*>::iterator iter = remove_these_nodes.begin();
- iter != remove_these_nodes.end(); ++iter)
- {
- LLSelectNode* nodep = *iter;
- mHighlightedObjects->removeNode(nodep);
- }
-
- // remove all root objects already being highlighted
- for (std::vector<LLViewerObject*>::iterator iter = remove_these_roots.begin();
- iter != remove_these_roots.end(); ++iter)
- {
- LLViewerObject* objectp = *iter;
- roots.erase(objectp);
- }
-
- // add all new objects in rectangle selection
- for (std::set<LLViewerObject*>::iterator iter = roots.begin();
- iter != roots.end(); iter++)
- {
- LLViewerObject* objectp = *iter;
- if (!canSelectObject(objectp))
- {
- continue;
- }
-
- LLSelectNode* rect_select_root_node = new LLSelectNode(objectp, true);
- rect_select_root_node->selectAllTEs(true);
-
- if (!select_linked_set)
- {
- rect_select_root_node->mIndividualSelection = true;
- }
- else
- {
- LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child_objectp = *iter;
-
- if (!canSelectObject(child_objectp))
- {
- continue;
- }
-
- LLSelectNode* rect_select_node = new LLSelectNode(child_objectp, true);
- rect_select_node->selectAllTEs(true);
- mHighlightedObjects->addNodeAtEnd(rect_select_node);
- }
- }
-
- // Add the root last, to preserve order for link operations.
- mHighlightedObjects->addNodeAtEnd(rect_select_root_node);
- }
-
- num_sils_genned = 0;
-
- // render silhouettes for highlighted objects
- //bool subtracting_from_selection = (gKeyboard->currentMask(true) == MASK_CONTROL);
- for (S32 pass = 0; pass < 2; pass++)
- {
- for (LLObjectSelection::iterator iter = mHighlightedObjects->begin();
- iter != mHighlightedObjects->end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* objectp = node->getObject();
- if (!objectp)
- continue;
-
- // do roots first, then children so that root flags are cleared ASAP
- bool roots_only = (pass == 0);
- bool is_root = objectp->isRootEdit();
- if (roots_only != is_root)
- {
- continue;
- }
-
- if (!node->mSilhouetteExists
- || objectp->isChanged(LLXform::SILHOUETTE)
- || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE)))
- {
- if (num_sils_genned++ < MAX_SILS_PER_FRAME)
- {
- generateSilhouette(node, LLViewerCamera::getInstance()->getOrigin());
- changed_objects.push_back(objectp);
- }
- else if (objectp->isAttachment() && objectp->getRootEdit()->mDrawable.notNull())
- {
- //RN: hack for orthogonal projection of HUD attachments
- LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent();
- if (attachment_pt && attachment_pt->getIsHUDAttachment())
- {
- LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f);
- generateSilhouette(node, camera_pos);
- }
- }
- }
- //LLColor4 highlight_color;
- //
- //if (subtracting_from_selection)
- //{
- // node->renderOneSilhouette(LLColor4::red);
- //}
- //else if (!objectp->isSelected())
- //{
- // highlight_color = objectp->isRoot() ? sHighlightParentColor : sHighlightChildColor;
- // node->renderOneSilhouette(highlight_color);
- //}
- }
- }
- //mSilhouetteImagep->unbindTexture(0, GL_TEXTURE_2D);
- }
- else
- {
- mHighlightedObjects->deleteAllNodes();
- }
-
- for (std::vector<LLViewerObject*>::iterator iter = changed_objects.begin();
- iter != changed_objects.end(); ++iter)
- {
- // clear flags after traversing node list (as child objects need to refer to parent flags, etc)
- LLViewerObject* objectp = *iter;
- objectp->clearChanged(LLXform::MOVED | LLXform::SILHOUETTE);
- }
-}
-
-void LLSelectMgr::updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects)
-{
- if (object_handle->getNumNodes())
- {
- //gGLSPipelineSelection.set();
-
- //mSilhouetteImagep->bindTexture();
- //glAlphaFunc(GL_GREATER, sHighlightAlphaTest);
-
- for (S32 pass = 0; pass < 2; pass++)
- {
- for (LLObjectSelection::iterator iter = object_handle->begin();
- iter != object_handle->end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* objectp = node->getObject();
- if (!objectp)
- continue;
- // do roots first, then children so that root flags are cleared ASAP
- bool roots_only = (pass == 0);
- bool is_root = (objectp->isRootEdit());
- if (roots_only != is_root || objectp->mDrawable.isNull())
- {
- continue;
- }
-
- if (!node->mSilhouetteExists
- || objectp->isChanged(LLXform::SILHOUETTE)
- || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE)))
- {
- if (num_sils_genned++ < MAX_SILS_PER_FRAME)// && objectp->mDrawable->isVisible())
- {
- generateSilhouette(node, LLViewerCamera::getInstance()->getOrigin());
- changed_objects.push_back(objectp);
- }
- else if (objectp->isAttachment())
- {
- //RN: hack for orthogonal projection of HUD attachments
- LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent();
- if (attachment_pt && attachment_pt->getIsHUDAttachment())
- {
- LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f);
- generateSilhouette(node, camera_pos);
- }
- }
- }
- }
- }
- }
-}
-void LLSelectMgr::renderSilhouettes(bool for_hud)
-{
- if (!mRenderSilhouettes || !mRenderHighlightSelections)
- {
- return;
- }
-
- gGL.getTexUnit(0)->bind(mSilhouetteImagep);
- LLGLSPipelineSelection gls_select;
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
-
- if (isAgentAvatarValid() && for_hud)
- {
- LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
-
- F32 cur_zoom = gAgentCamera.mHUDCurZoom;
-
- // set up transform to encompass bounding box of HUD
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.pushMatrix();
- gGL.loadIdentity();
- F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
- gGL.ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.pushUIMatrix();
- gGL.loadUIIdentity();
- gGL.loadIdentity();
- gGL.loadMatrix(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
- gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
- gGL.scalef(cur_zoom, cur_zoom, cur_zoom);
- }
-
- bool wireframe_selection = (gFloaterTools && gFloaterTools->getVisible()) || LLSelectMgr::sRenderHiddenSelections;
- F32 fogCfx = (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal() - gAgentCamera.getCameraPositionGlobal()).magVec() / (LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec() * 4), 0.0, 1.0);
-
- static LLColor4 sParentColor = LLColor4(sSilhouetteParentColor[VRED], sSilhouetteParentColor[VGREEN], sSilhouetteParentColor[VBLUE], LLSelectMgr::sHighlightAlpha);
- static LLColor4 sChildColor = LLColor4(sSilhouetteChildColor[VRED], sSilhouetteChildColor[VGREEN], sSilhouetteChildColor[VBLUE], LLSelectMgr::sHighlightAlpha);
-
- auto renderMeshSelection_f = [fogCfx, wireframe_selection](LLSelectNode* node, LLViewerObject* objectp, LLColor4 hlColor)
- {
- LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
- if (shader)
- {
- gDebugProgram.bind();
- }
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
-
- bool is_hud_object = objectp->isHUDAttachment();
-
- if (!is_hud_object)
- {
- gGL.loadIdentity();
- gGL.multMatrix(gGLModelView);
- }
-
- if (objectp->mDrawable->isActive())
- {
- gGL.multMatrix((F32*)objectp->getRenderMatrix().mMatrix);
- }
- else if (!is_hud_object)
- {
- LLVector3 trans = objectp->getRegion()->getOriginAgent();
- gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
- }
-
- bool bRenderHidenSelection = node->isTransient() ? false : LLSelectMgr::sRenderHiddenSelections;
-
-
- LLVOVolume* vobj = objectp->mDrawable->getVOVolume();
- if (vobj)
- {
- LLVertexBuffer::unbind();
- gGL.pushMatrix();
- gGL.multMatrix((F32*)vobj->getRelativeXform().mMatrix);
-
- if (objectp->mDrawable->isState(LLDrawable::RIGGED))
- {
- vobj->updateRiggedVolume(true);
- }
- }
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); // avatars have TEs but no faces
- for (S32 te = 0; te < num_tes; ++te)
- {
- if (node->isTESelected(te))
- {
- objectp->mDrawable->getFace(te)->renderOneWireframe(hlColor, fogCfx, wireframe_selection, bRenderHidenSelection, nullptr != shader);
- }
- }
-
- gGL.popMatrix();
- gGL.popMatrix();
-
- glLineWidth(1.f);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
- if (shader)
- {
- shader->bind();
- }
- };
-
- if (mSelectedObjects->getNumNodes())
- {
- LLUUID inspect_item_id= LLUUID::null;
- LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance<LLFloaterInspect>("inspect");
- if(inspect_instance && inspect_instance->getVisible())
- {
- inspect_item_id = inspect_instance->getSelectedUUID();
- }
- else
- {
- LLSidepanelTaskInfo *panel_task_info = LLSidepanelTaskInfo::getActivePanel();
- if (panel_task_info)
- {
- inspect_item_id = panel_task_info->getSelectedUUID();
- }
- }
-
- LLUUID focus_item_id = LLViewerMediaFocus::getInstance()->getFocusedObjectID();
- for (S32 pass = 0; pass < 2; pass++)
- {
- for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
- iter != mSelectedObjects->end(); iter++)
- {
- LLSelectNode* node = *iter;
-
- if (getTEMode() && !node->hasSelectedTE())
- continue;
-
- LLViewerObject* objectp = node->getObject();
- if (!objectp)
- continue;
-
- if (objectp->mDrawable
- && objectp->mDrawable->getVOVolume()
- && objectp->mDrawable->getVOVolume()->isMesh())
- {
- LLColor4 hlColor = objectp->isRootEdit() ? sParentColor : sChildColor;
- if (objectp->getID() == inspect_item_id)
- {
- hlColor = sHighlightInspectColor;
- }
- else if (node->isTransient())
- {
- hlColor = sContextSilhouetteColor;
- }
- renderMeshSelection_f(node, objectp, hlColor);
- }
- else
- {
- if (objectp->isHUDAttachment() != for_hud)
- {
- continue;
- }
- if (objectp->getID() == focus_item_id)
- {
- node->renderOneSilhouette(gFocusMgr.getFocusColor());
- }
- else if (objectp->getID() == inspect_item_id)
- {
- node->renderOneSilhouette(sHighlightInspectColor);
- }
- else if (node->isTransient())
- {
- bool oldHidden = LLSelectMgr::sRenderHiddenSelections;
- LLSelectMgr::sRenderHiddenSelections = false;
- node->renderOneSilhouette(sContextSilhouetteColor);
- LLSelectMgr::sRenderHiddenSelections = oldHidden;
- }
- else if (objectp->isRootEdit())
- {
- node->renderOneSilhouette(sSilhouetteParentColor);
- }
- else
- {
- node->renderOneSilhouette(sSilhouetteChildColor);
- }
- }
- } //for all selected node's
- } //for pass
- }
-
- if (mHighlightedObjects->getNumNodes())
- {
- // render silhouettes for highlighted objects
- bool subtracting_from_selection = (gKeyboard->currentMask(true) == MASK_CONTROL);
- for (S32 pass = 0; pass < 2; pass++)
- {
- for (LLObjectSelection::iterator iter = mHighlightedObjects->begin();
- iter != mHighlightedObjects->end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* objectp = node->getObject();
- if (!objectp)
- continue;
- if (objectp->isHUDAttachment() != for_hud)
- {
- continue;
- }
-
- LLColor4 highlight_color = objectp->isRoot() ? sHighlightParentColor : sHighlightChildColor;
- if (objectp->mDrawable
- && objectp->mDrawable->getVOVolume()
- && objectp->mDrawable->getVOVolume()->isMesh())
- {
- renderMeshSelection_f(node, objectp, subtracting_from_selection ? LLColor4::red : highlight_color);
- }
- else if (subtracting_from_selection)
- {
- node->renderOneSilhouette(LLColor4::red);
- }
- else if (!objectp->isSelected())
- {
- node->renderOneSilhouette(highlight_color);
- }
- }
- }
- }
-
- if (isAgentAvatarValid() && for_hud)
- {
- gGL.matrixMode(LLRender::MM_PROJECTION);
- gGL.popMatrix();
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.popMatrix();
- gGL.popUIMatrix();
- stop_glerror();
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-}
-
-void LLSelectMgr::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
-{
- LLViewerObject* objectp = nodep->getObject();
-
- if (objectp && objectp->getPCode() == LL_PCODE_VOLUME)
- {
- ((LLVOVolume*)objectp)->generateSilhouette(nodep, view_point);
- }
-}
-
-//
-// Utility classes
-//
-LLSelectNode::LLSelectNode(LLViewerObject* object, bool glow)
-: mObject(object),
- mIndividualSelection(false),
- mTransient(false),
- mValid(false),
- mPermissions(new LLPermissions()),
- mInventorySerial(0),
- mSilhouetteExists(false),
- mDuplicated(false),
- mTESelectMask(0),
- mLastTESelected(0),
- mName(LLStringUtil::null),
- mDescription(LLStringUtil::null),
- mTouchName(LLStringUtil::null),
- mSitName(LLStringUtil::null),
- mCreationDate(0)
-{
- saveColors();
- saveShinyColors();
-}
-
-LLSelectNode::LLSelectNode(const LLSelectNode& nodep)
-{
- mTESelectMask = nodep.mTESelectMask;
- mLastTESelected = nodep.mLastTESelected;
-
- mIndividualSelection = nodep.mIndividualSelection;
-
- mValid = nodep.mValid;
- mTransient = nodep.mTransient;
- mPermissions = new LLPermissions(*nodep.mPermissions);
- mSaleInfo = nodep.mSaleInfo;;
- mAggregatePerm = nodep.mAggregatePerm;
- mAggregateTexturePerm = nodep.mAggregateTexturePerm;
- mAggregateTexturePermOwner = nodep.mAggregateTexturePermOwner;
- mName = nodep.mName;
- mDescription = nodep.mDescription;
- mCategory = nodep.mCategory;
- mInventorySerial = 0;
- mSavedPositionLocal = nodep.mSavedPositionLocal;
- mSavedPositionGlobal = nodep.mSavedPositionGlobal;
- mSavedScale = nodep.mSavedScale;
- mSavedRotation = nodep.mSavedRotation;
- mDuplicated = nodep.mDuplicated;
- mDuplicatePos = nodep.mDuplicatePos;
- mDuplicateRot = nodep.mDuplicateRot;
- mItemID = nodep.mItemID;
- mFolderID = nodep.mFolderID;
- mFromTaskID = nodep.mFromTaskID;
- mTouchName = nodep.mTouchName;
- mSitName = nodep.mSitName;
- mCreationDate = nodep.mCreationDate;
-
- mSilhouetteVertices = nodep.mSilhouetteVertices;
- mSilhouetteNormals = nodep.mSilhouetteNormals;
- mSilhouetteExists = nodep.mSilhouetteExists;
- mObject = nodep.mObject;
-
- std::vector<LLColor4>::const_iterator color_iter;
- mSavedColors.clear();
- for (color_iter = nodep.mSavedColors.begin(); color_iter != nodep.mSavedColors.end(); ++color_iter)
- {
- mSavedColors.push_back(*color_iter);
- }
- mSavedShinyColors.clear();
- for (color_iter = nodep.mSavedShinyColors.begin(); color_iter != nodep.mSavedShinyColors.end(); ++color_iter)
- {
- mSavedShinyColors.push_back(*color_iter);
- }
-
- saveTextures(nodep.mSavedTextures);
- saveGLTFMaterials(nodep.mSavedGLTFMaterialIds, nodep.mSavedGLTFOverrideMaterials);
-}
-
-LLSelectNode::~LLSelectNode()
-{
- LLSelectMgr *manager = LLSelectMgr::getInstance();
- if (manager->mAllowSelectAvatar
- && (!mLastPositionLocal.isExactlyZero()
- || mLastRotation != LLQuaternion()))
- {
- LLViewerObject* object = getObject(); //isDead() check
- if (object && !object->getParent())
- {
- LLVOAvatar* avatar = object->asAvatar();
- if (avatar)
- {
- // Avatar was moved and needs to stay that way
- manager->mAvatarOverridesMap.emplace(avatar->getID(), LLSelectMgr::AvatarPositionOverride(mLastPositionLocal, mLastRotation, object));
- }
- }
- }
-
-
- delete mPermissions;
- mPermissions = NULL;
-}
-
-void LLSelectNode::selectAllTEs(bool b)
-{
- mTESelectMask = b ? TE_SELECT_MASK_ALL : 0x0;
- mLastTESelected = 0;
-}
-
-void LLSelectNode::selectTE(S32 te_index, bool selected)
-{
- if (te_index < 0 || te_index >= SELECT_MAX_TES)
- {
- return;
- }
- S32 mask = 0x1 << te_index;
- if(selected)
- {
- mTESelectMask |= mask;
- }
- else
- {
- mTESelectMask &= ~mask;
- }
- mLastTESelected = te_index;
-}
-
-bool LLSelectNode::isTESelected(S32 te_index) const
-{
- if (te_index < 0 || te_index >= mObject->getNumTEs())
- {
- return false;
- }
- return (mTESelectMask & (0x1 << te_index)) != 0;
-}
-
-S32 LLSelectNode::getLastSelectedTE() const
-{
- if (!isTESelected(mLastTESelected))
- {
- return -1;
- }
- return mLastTESelected;
-}
-
-LLViewerObject* LLSelectNode::getObject()
-{
- if (!mObject)
- {
- return NULL;
- }
- else if (mObject->isDead())
- {
- mObject = NULL;
- }
- return mObject;
-}
-
-void LLSelectNode::setObject(LLViewerObject* object)
-{
- mObject = object;
-}
-
-void LLSelectNode::saveColors()
-{
- if (mObject.notNull())
- {
- mSavedColors.clear();
- for (S32 i = 0; i < mObject->getNumTEs(); i++)
- {
- const LLTextureEntry* tep = mObject->getTE(i);
- mSavedColors.push_back(tep->getColor());
- }
- }
-}
-
-void LLSelectNode::saveShinyColors()
-{
- if (mObject.notNull())
- {
- mSavedShinyColors.clear();
- for (S32 i = 0; i < mObject->getNumTEs(); i++)
- {
- const LLMaterialPtr mat = mObject->getTE(i)->getMaterialParams();
- if (!mat.isNull())
- {
- mSavedShinyColors.push_back(mat->getSpecularLightColor());
- }
- else
- {
- mSavedShinyColors.push_back(LLColor4::white);
- }
- }
- }
-}
-
-void LLSelectNode::saveTextures(const uuid_vec_t& textures)
-{
- if (mObject.notNull())
- {
- mSavedTextures.clear();
-
- for (uuid_vec_t::const_iterator texture_it = textures.begin();
- texture_it != textures.end(); ++texture_it)
- {
- mSavedTextures.push_back(*texture_it);
- }
- }
-}
-
-void LLSelectNode::saveGLTFMaterials(const uuid_vec_t& materials, const gltf_materials_vec_t& override_materials)
-{
- if (mObject.notNull())
- {
- mSavedGLTFMaterialIds.clear();
- mSavedGLTFOverrideMaterials.clear();
-
- for (uuid_vec_t::const_iterator materials_it = materials.begin();
- materials_it != materials.end(); ++materials_it)
- {
- mSavedGLTFMaterialIds.push_back(*materials_it);
- }
-
- for (gltf_materials_vec_t::const_iterator mat_it = override_materials.begin();
- mat_it != override_materials.end(); ++mat_it)
- {
- mSavedGLTFOverrideMaterials.push_back(*mat_it);
- }
- }
-}
-
-void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query)
-{
- mTextureScaleRatios.clear();
-
- if (mObject.notNull())
- {
-
- LLVector3 scale = mObject->getScale();
-
- for (U8 i = 0; i < mObject->getNumTEs(); i++)
- {
- F32 diffuse_s = 1.0f;
- F32 diffuse_t = 1.0f;
-
- LLVector3 v;
- const LLTextureEntry* tep = mObject->getTE(i);
- if (!tep)
- continue;
-
- U32 s_axis = VX;
- U32 t_axis = VY;
- LLPrimitive::getTESTAxes(i, &s_axis, &t_axis);
-
- tep->getScale(&diffuse_s,&diffuse_t);
-
- if (tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR)
- {
- v.mV[s_axis] = diffuse_s*scale.mV[s_axis];
- v.mV[t_axis] = diffuse_t*scale.mV[t_axis];
- mTextureScaleRatios.push_back(v);
- }
- else
- {
- v.mV[s_axis] = diffuse_s/scale.mV[s_axis];
- v.mV[t_axis] = diffuse_t/scale.mV[t_axis];
- mTextureScaleRatios.push_back(v);
- }
- }
- }
-}
-
-
-// This implementation should be similar to LLTask::allowOperationOnTask
-bool LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const
-{
- // Extract ownership.
- bool object_is_group_owned = false;
- LLUUID object_owner_id;
- mPermissions->getOwnership(object_owner_id, object_is_group_owned);
-
- // Operations on invalid or public objects is not allowed.
- if (!mObject || (mObject->isDead()) || !mPermissions->isOwned())
- {
- return false;
- }
-
- // The transfer permissions can never be given through proxy.
- if (PERM_TRANSFER == op)
- {
- // The owner of an agent-owned object can transfer to themselves.
- if ( !object_is_group_owned
- && (gAgent.getID() == object_owner_id) )
- {
- return true;
- }
- else
- {
- // Otherwise check aggregate permissions.
- return mObject->permTransfer();
- }
- }
-
- if (PERM_MOVE == op
- || PERM_MODIFY == op)
- {
- // only owners can move or modify their attachments
- // no proxy allowed.
- if (mObject->isAttachment() && object_owner_id != gAgent.getID())
- {
- return false;
- }
- }
-
- // Calculate proxy_agent_id and group_id to use for permissions checks.
- // proxy_agent_id may be set to the object owner through group powers.
- // group_id can only be set to the object's group, if the agent is in that group.
- LLUUID group_id = LLUUID::null;
- LLUUID proxy_agent_id = gAgent.getID();
-
- // Gods can always operate.
- if (gAgent.isGodlike())
- {
- return true;
- }
-
- // Check if the agent is in the same group as the object.
- LLUUID object_group_id = mPermissions->getGroup();
- if (object_group_id.notNull() &&
- gAgent.isInGroup(object_group_id))
- {
- // Assume the object's group during this operation.
- group_id = object_group_id;
- }
-
- // Only allow proxy powers for PERM_COPY if the actual agent can
- // receive the item (ie has PERM_TRANSFER permissions).
- // NOTE: op == PERM_TRANSFER has already been handled, but if
- // that ever changes we need to BLOCK proxy powers for PERM_TRANSFER. DK 03/28/06
- if (PERM_COPY != op || mPermissions->allowTransferTo(gAgent.getID()))
- {
- // Check if the agent can assume ownership through group proxy or agent-granted proxy.
- if ( ( object_is_group_owned
- && gAgent.hasPowerInGroup(object_owner_id, group_proxy_power))
- // Only allow proxy for move, modify, and copy.
- || ( (PERM_MOVE == op || PERM_MODIFY == op || PERM_COPY == op)
- && (!object_is_group_owned
- && gAgent.isGrantedProxy(*mPermissions))))
- {
- // This agent is able to assume the ownership role for this operation.
- proxy_agent_id = object_owner_id;
- }
- }
-
- // We now have max ownership information.
- if (PERM_OWNER == op)
- {
- // This this was just a check for ownership, we can now return the answer.
- return proxy_agent_id == object_owner_id;
- }
-
- // check permissions to see if the agent can operate
- return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
-}
-
-//-----------------------------------------------------------------------------
-// renderOneSilhouette()
-//-----------------------------------------------------------------------------
-void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
-{
- LLViewerObject* objectp = getObject();
- if (!objectp)
- {
- return;
- }
-
- LLDrawable* drawable = objectp->mDrawable;
- if(!drawable)
- {
- return;
- }
-
- LLVOVolume* vobj = drawable->getVOVolume();
- if (vobj && vobj->isMesh())
- {
- //This check (if(...)) with assert here just for ensure that this situation will not happens, and can be removed later. For example on the next release.
- llassert(!"renderOneWireframe() was removed SL-10194");
- return;
- }
-
- if (!mSilhouetteExists)
- {
- return;
- }
-
- bool is_hud_object = objectp->isHUDAttachment();
-
- if (mSilhouetteVertices.size() == 0 || mSilhouetteNormals.size() != mSilhouetteVertices.size())
- {
- return;
- }
-
-
- LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
- if (shader)
- { //use UI program for selection highlights (texture color modulated by vertex color)
- gUIProgram.bind();
- }
-
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gGL.pushMatrix();
- gGL.pushUIMatrix();
- gGL.loadUIIdentity();
-
- if (!is_hud_object)
- {
- gGL.loadIdentity();
- gGL.multMatrix(gGLModelView);
- }
-
-
- if (drawable->isActive())
- {
- gGL.multMatrix((F32*) objectp->getRenderMatrix().mMatrix);
- }
-
- LLVolume *volume = objectp->getVolume();
- if (volume)
- {
- F32 silhouette_thickness;
- if (isAgentAvatarValid() && is_hud_object)
- {
- silhouette_thickness = LLSelectMgr::sHighlightThickness / gAgentCamera.mHUDCurZoom;
- }
- else
- {
- LLVector3 view_vector = LLViewerCamera::getInstance()->getOrigin() - objectp->getRenderPosition();
- silhouette_thickness = view_vector.magVec() * LLSelectMgr::sHighlightThickness * (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV());
- }
- F32 animationTime = (F32)LLFrameTimer::getElapsedSeconds();
-
- F32 u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f);
- F32 v_coord = 1.f - fmod(animationTime * LLSelectMgr::sHighlightVAnim, 1.f);
- F32 u_divisor = 1.f / ((F32)(mSilhouetteVertices.size() - 1));
-
- if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible())
- {
- gGL.flush();
- gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE);
-
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
- gGL.flush();
- gGL.begin(LLRender::LINES);
- {
- gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
-
- for(S32 i = 0; i < mSilhouetteVertices.size(); i += 2)
- {
- u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
- gGL.texCoord2f( u_coord, v_coord );
- gGL.vertex3fv( mSilhouetteVertices[i].mV);
- u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
- gGL.texCoord2f( u_coord, v_coord );
- gGL.vertex3fv(mSilhouetteVertices[i+1].mV);
- }
- }
- gGL.end();
- u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f);
- }
-
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- gGL.begin(LLRender::TRIANGLES);
- {
- for(S32 i = 0; i < mSilhouetteVertices.size(); i+=2)
- {
- if (!mSilhouetteNormals[i].isFinite() ||
- !mSilhouetteNormals[i+1].isFinite())
- { //skip skewed segments
- continue;
- }
-
- LLVector3 v[4];
- LLVector2 tc[4];
- v[0] = mSilhouetteVertices[i] + (mSilhouetteNormals[i] * silhouette_thickness);
- tc[0].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale);
-
- v[1] = mSilhouetteVertices[i];
- tc[1].set(u_coord, v_coord);
-
- u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
-
- v[2] = mSilhouetteVertices[i+1] + (mSilhouetteNormals[i+1] * silhouette_thickness);
- tc[2].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale);
-
- v[3] = mSilhouetteVertices[i+1];
- tc[3].set(u_coord,v_coord);
-
- gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
- gGL.texCoord2fv(tc[0].mV);
- gGL.vertex3fv( v[0].mV );
-
- gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha);
- gGL.texCoord2fv( tc[1].mV );
- gGL.vertex3fv( v[1].mV );
-
- gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
- gGL.texCoord2fv( tc[2].mV );
- gGL.vertex3fv( v[2].mV );
-
- gGL.vertex3fv( v[2].mV );
-
- gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha);
- gGL.texCoord2fv( tc[1].mV );
- gGL.vertex3fv( v[1].mV );
-
- gGL.texCoord2fv( tc[3].mV );
- gGL.vertex3fv( v[3].mV );
- }
- }
- gGL.end();
- gGL.flush();
- }
- gGL.popMatrix();
- gGL.popUIMatrix();
-
- if (shader)
- {
- shader->bind();
- }
-}
-
-//
-// Utility Functions
-//
-
-// *DEPRECATED: See header comment.
-void dialog_refresh_all()
-{
- // This is the easiest place to fire the update signal, as it will
- // make cleaning up the functions below easier. Also, sometimes entities
- // outside the selection manager change properties of selected objects
- // and call into this function. Yuck.
- LLSelectMgr::getInstance()->mUpdateSignal();
-
- // *TODO: Eliminate all calls into outside classes below, make those
- // objects register with the update signal.
-
- gFloaterTools->dirty();
-
- gMenuObject->needsArrange();
-
- if( gMenuAttachmentSelf->getVisible() )
- {
- gMenuAttachmentSelf->arrange();
- }
- if( gMenuAttachmentOther->getVisible() )
- {
- gMenuAttachmentOther->arrange();
- }
-
- LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance<LLFloaterInspect>("inspect");
- if(inspect_instance)
- {
- inspect_instance->dirty();
- }
-
- LLSidepanelTaskInfo *panel_task_info = LLSidepanelTaskInfo::getActivePanel();
- if (panel_task_info)
- {
- panel_task_info->dirty();
- }
-}
-
-S32 get_family_count(LLViewerObject *parent)
-{
- if (!parent)
- {
- LL_WARNS() << "Trying to get_family_count on null parent!" << LL_ENDL;
- }
- S32 count = 1; // for this object
- LLViewerObject::const_child_list_t& child_list = parent->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child = *iter;
-
- if (!child)
- {
- LL_WARNS() << "Family object has NULL child! Show Doug." << LL_ENDL;
- }
- else if (child->isDead())
- {
- LL_WARNS() << "Family object has dead child object. Show Doug." << LL_ENDL;
- }
- else
- {
- if (LLSelectMgr::getInstance()->canSelectObject(child))
- {
- count += get_family_count( child );
- }
- }
- }
- return count;
-}
-
-//-----------------------------------------------------------------------------
-// updateSelectionCenter
-//
-// FIXME this is a grab bag of functionality only some of which has to do
-// with the selection center
-// -----------------------------------------------------------------------------
-void LLSelectMgr::updateSelectionCenter()
-{
- const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection
- // center (tractor beam)
-
- // override any avatar updates received
- // Works only if avatar was repositioned
- // and edit floater is visible
- overrideAvatarUpdates();
- //override any object updates received
- //for selected objects
- overrideObjectUpdates();
-
- LLViewerObject* object = mSelectedObjects->getFirstObject();
- if (!object)
- {
- // nothing selected, probably grabbing
- // Ignore by setting to avatar origin.
- mSelectionCenterGlobal.clearVec();
- mShowSelection = false;
- mSelectionBBox = LLBBox();
- resetAgentHUDZoom();
- }
- else
- {
- mSelectedObjects->mSelectType = getSelectTypeForObject(object);
-
- if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid())
- {
- // reset hud ZOOM
- resetAgentHUDZoom();
- }
-
- mShowSelection = false;
- LLBBox bbox;
-
- // have stuff selected
- LLVector3d select_center;
- // keep a list of jointed objects for showing the joint HUDEffects
-
- // Initialize the bounding box to the root prim, so the BBox orientation
- // matches the root prim's (affecting the orientation of the manipulators).
- bbox.addBBoxAgent( (mSelectedObjects->getFirstRootObject(true))->getBoundingBoxAgent() );
-
- for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
- iter != mSelectedObjects->end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if (!object)
- continue;
-
- LLViewerObject *root = object->getRootEdit();
- if (mSelectedObjects->mSelectType == SELECT_TYPE_WORLD && // not an attachment
- !root->isChild(gAgentAvatarp) && // not the object you're sitting on
- !object->isAvatar()) // not another avatar
- {
- mShowSelection = true;
- }
-
- bbox.addBBoxAgent( object->getBoundingBoxAgent() );
- }
-
- LLVector3 bbox_center_agent = bbox.getCenterAgent();
- mSelectionCenterGlobal = gAgent.getPosGlobalFromAgent(bbox_center_agent);
- mSelectionBBox = bbox;
-
- }
-
- if ( !(gAgentID == LLUUID::null))
- {
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
- if (mShowSelection)
- {
- LLVector3d select_center_global;
-
- if( tool->isEditing() )
- {
- select_center_global = tool->getEditingPointGlobal();
- }
- else
- {
- select_center_global = mSelectionCenterGlobal;
- }
-
- // Send selection center if moved beyond threshold (used to animate tractor beam)
- LLVector3d diff;
- diff = select_center_global - mLastSentSelectionCenterGlobal;
-
- if ( diff.magVecSquared() > MOVE_SELECTION_THRESHOLD*MOVE_SELECTION_THRESHOLD )
- {
- // Transmit updated selection center
- mLastSentSelectionCenterGlobal = select_center_global;
- }
- }
- }
-
- // give up edit menu if no objects selected
- if (gEditMenuHandler == this && mSelectedObjects->getObjectCount() == 0)
- {
- gEditMenuHandler = NULL;
- }
-
- pauseAssociatedAvatars();
-}
-
-//-----------------------------------------------------------------------------
-// pauseAssociatedAvatars
-//
-// If the selection includes an attachment or an animated object, the
-// associated avatars should pause their animations until they are no
-// longer selected.
-//-----------------------------------------------------------------------------
-void LLSelectMgr::pauseAssociatedAvatars()
-{
- mPauseRequests.clear();
-
- for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
- iter != mSelectedObjects->end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if (!object)
- continue;
-
- mSelectedObjects->mSelectType = getSelectTypeForObject(object);
-
- LLVOAvatar* parent_av = NULL;
- if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT)
- {
- // Selection can be obsolete, confirm that this is an attachment
- // and find parent avatar
- parent_av = object->getAvatarAncestor();
- }
-
- // Can be both an attachment and animated object
- if (parent_av)
- {
- // It's an attachment. Pause the avatar it's attached to.
- mPauseRequests.push_back(parent_av->requestPause());
- }
-
- if (object->isAnimatedObject() && object->getControlAvatar())
- {
- // It's an animated object. Pause the control avatar.
- mPauseRequests.push_back(object->getControlAvatar()->requestPause());
- }
- }
-}
-
-void LLSelectMgr::updatePointAt()
-{
- if (mShowSelection)
- {
- if (mSelectedObjects->getObjectCount())
- {
- LLVector3 select_offset;
- const LLPickInfo& pick = gViewerWindow->getLastPick();
- LLViewerObject *click_object = pick.getObject();
- if (click_object && click_object->isSelected())
- {
- // clicked on another object in our selection group, use that as target
- select_offset.setVec(pick.mObjectOffset);
- select_offset.rotVec(~click_object->getRenderRotation());
-
- gAgentCamera.setPointAt(POINTAT_TARGET_SELECT, click_object, select_offset);
- gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, click_object, select_offset);
- }
- else
- {
- // didn't click on an object this time, revert to pointing at center of first object
- gAgentCamera.setPointAt(POINTAT_TARGET_SELECT, mSelectedObjects->getFirstObject());
- gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, mSelectedObjects->getFirstObject());
- }
- }
- else
- {
- gAgentCamera.setPointAt(POINTAT_TARGET_CLEAR);
- gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
- }
- }
- else
- {
- gAgentCamera.setPointAt(POINTAT_TARGET_CLEAR);
- gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
- }
-}
-
-//-----------------------------------------------------------------------------
-// getBBoxOfSelection()
-//-----------------------------------------------------------------------------
-LLBBox LLSelectMgr::getBBoxOfSelection() const
-{
- return mSelectionBBox;
-}
-
-
-//-----------------------------------------------------------------------------
-// canUndo()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::canUndo() const
-{
- // Can edit or can move
- return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstUndoEnabledObject() != NULL; // HACK: casting away constness - MG;
-}
-
-//-----------------------------------------------------------------------------
-// undo()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::undo()
-{
- bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
- LLUUID group_id(gAgent.getGroupID());
- sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
-}
-
-//-----------------------------------------------------------------------------
-// canRedo()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::canRedo() const
-{
- return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstEditableObject() != NULL; // HACK: casting away constness - MG
-}
-
-//-----------------------------------------------------------------------------
-// redo()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::redo()
-{
- bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
- LLUUID group_id(gAgent.getGroupID());
- sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
-}
-
-//-----------------------------------------------------------------------------
-// canDoDelete()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::canDoDelete() const
-{
- bool can_delete = false;
- // This function is "logically const" - it does not change state in
- // a way visible outside the selection manager.
- LLSelectMgr* self = const_cast<LLSelectMgr*>(this);
- LLViewerObject* obj = self->mSelectedObjects->getFirstDeleteableObject();
- // Note: Can only delete root objects (see getFirstDeleteableObject() for more info)
- if (obj!= NULL)
- {
- // all the faces needs to be selected
- if(self->mSelectedObjects->contains(obj,SELECT_ALL_TES ))
- {
- can_delete = true;
- }
- }
-
- return can_delete;
-}
-
-//-----------------------------------------------------------------------------
-// doDelete()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::doDelete()
-{
- selectDelete();
-}
-
-//-----------------------------------------------------------------------------
-// canDeselect()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::canDeselect() const
-{
- return !mSelectedObjects->isEmpty();
-}
-
-//-----------------------------------------------------------------------------
-// deselect()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::deselect()
-{
- deselectAll();
-}
-//-----------------------------------------------------------------------------
-// canDuplicate()
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::canDuplicate() const
-{
- return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG
-}
-//-----------------------------------------------------------------------------
-// duplicate()
-//-----------------------------------------------------------------------------
-void LLSelectMgr::duplicate()
-{
- LLVector3 offset(0.5f, 0.5f, 0.f);
- selectDuplicate(offset, true);
-}
-
-ESelectType LLSelectMgr::getSelectTypeForObject(LLViewerObject* object)
-{
- if (!object)
- {
- return SELECT_TYPE_WORLD;
- }
- if (object->isHUDAttachment())
- {
- return SELECT_TYPE_HUD;
- }
- else if (object->isAttachment())
- {
- return SELECT_TYPE_ATTACHMENT;
- }
- else
- {
- return SELECT_TYPE_WORLD;
- }
-}
-
-void LLSelectMgr::validateSelection()
-{
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- if (!LLSelectMgr::getInstance()->canSelectObject(object))
- {
- LLSelectMgr::getInstance()->deselectObjectOnly(object);
- }
- return true;
- }
- } func;
- getSelection()->applyToObjects(&func);
-}
-
-bool LLSelectMgr::canSelectObject(LLViewerObject* object, bool ignore_select_owned)
-{
- // Never select dead objects
- if (!object || object->isDead())
- {
- return false;
- }
-
- if (mForceSelection)
- {
- return true;
- }
-
- if(!ignore_select_owned)
- {
- if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) ||
- (gSavedSettings.getBOOL("SelectMovableOnly") && (!object->permMove() || object->isPermanentEnforced())))
- {
- // only select my own objects
- return false;
- }
- }
-
- // Can't select orphans
- if (object->isOrphaned()) return false;
-
- // Can't select avatars
- if (object->isAvatar()) return false;
-
- // Can't select land
- if (object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) return false;
-
- ESelectType selection_type = getSelectTypeForObject(object);
- if (mSelectedObjects->getObjectCount() > 0 && mSelectedObjects->mSelectType != selection_type) return false;
-
- return true;
-}
-
-bool LLSelectMgr::setForceSelection(bool force)
-{
- std::swap(mForceSelection,force);
- return force;
-}
-
-void LLSelectMgr::resetAgentHUDZoom()
-{
- if (gAgentCamera.mHUDTargetZoom != 1)
- {
- gAgentCamera.mHUDTargetZoom = 1.f;
- gAgentCamera.mHUDCurZoom = 1.f;
- }
-}
-
-void LLSelectMgr::getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const
-{
- target_zoom = gAgentCamera.mHUDTargetZoom;
- current_zoom = gAgentCamera.mHUDCurZoom;
-}
-
-void LLSelectMgr::setAgentHUDZoom(F32 target_zoom, F32 current_zoom)
-{
- gAgentCamera.mHUDTargetZoom = target_zoom;
- gAgentCamera.mHUDCurZoom = current_zoom;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Object selection iterator helpers
-/////////////////////////////////////////////////////////////////////////////
-bool LLObjectSelection::is_root::operator()(LLSelectNode *node)
-{
- LLViewerObject* object = node->getObject();
- return (object != NULL) && !node->mIndividualSelection && (object->isRootEdit());
-}
-
-bool LLObjectSelection::is_valid_root::operator()(LLSelectNode *node)
-{
- LLViewerObject* object = node->getObject();
- return (object != NULL) && node->mValid && !node->mIndividualSelection && (object->isRootEdit());
-}
-
-bool LLObjectSelection::is_root_object::operator()(LLSelectNode *node)
-{
- LLViewerObject* object = node->getObject();
- return (object != NULL) && (object->isRootEdit());
-}
-
-LLObjectSelection::LLObjectSelection() :
- LLRefCount(),
- mSelectType(SELECT_TYPE_WORLD)
-{
-}
-
-LLObjectSelection::~LLObjectSelection()
-{
- deleteAllNodes();
-}
-
-void LLObjectSelection::cleanupNodes()
-{
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); )
- {
- list_t::iterator curiter = iter++;
- LLSelectNode* node = *curiter;
- if (node->getObject() == NULL || node->getObject()->isDead())
- {
- mList.erase(curiter);
- delete node;
- }
- }
-}
-
-void LLObjectSelection::updateEffects()
-{
-}
-
-S32 LLObjectSelection::getNumNodes()
-{
- return mList.size();
-}
-
-void LLObjectSelection::addNode(LLSelectNode *nodep)
-{
- llassert_always(nodep->getObject() && !nodep->getObject()->isDead());
- mList.push_front(nodep);
- mSelectNodeMap[nodep->getObject()] = nodep;
-}
-
-void LLObjectSelection::addNodeAtEnd(LLSelectNode *nodep)
-{
- llassert_always(nodep->getObject() && !nodep->getObject()->isDead());
- mList.push_back(nodep);
- mSelectNodeMap[nodep->getObject()] = nodep;
-}
-
-void LLObjectSelection::moveNodeToFront(LLSelectNode *nodep)
-{
- mList.remove(nodep);
- mList.push_front(nodep);
-}
-
-void LLObjectSelection::removeNode(LLSelectNode *nodep)
-{
- mSelectNodeMap.erase(nodep->getObject());
- if (nodep->getObject() == mPrimaryObject)
- {
- mPrimaryObject = NULL;
- }
- nodep->setObject(NULL); // Will get erased in cleanupNodes()
- mList.remove(nodep);
-}
-
-void LLObjectSelection::deleteAllNodes()
-{
- std::for_each(mList.begin(), mList.end(), DeletePointer());
- mList.clear();
- mSelectNodeMap.clear();
- mPrimaryObject = NULL;
-}
-
-LLSelectNode* LLObjectSelection::findNode(LLViewerObject* objectp)
-{
- std::map<LLPointer<LLViewerObject>, LLSelectNode*>::iterator found_it = mSelectNodeMap.find(objectp);
- if (found_it != mSelectNodeMap.end())
- {
- return found_it->second;
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// isEmpty()
-//-----------------------------------------------------------------------------
-bool LLObjectSelection::isEmpty() const
-{
- return (mList.size() == 0);
-}
-
-
-//-----------------------------------------------------------------------------
-// getObjectCount() - returns number of non null objects
-//-----------------------------------------------------------------------------
-S32 LLObjectSelection::getObjectCount()
-{
- cleanupNodes();
- S32 count = mList.size();
-
- return count;
-}
-
-F32 LLObjectSelection::getSelectedObjectCost()
-{
- cleanupNodes();
- F32 cost = 0.f;
-
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
-
- if (object)
- {
- cost += object->getObjectCost();
- }
- }
-
- return cost;
-}
-
-F32 LLObjectSelection::getSelectedLinksetCost()
-{
- cleanupNodes();
- F32 cost = 0.f;
-
- std::set<LLViewerObject*> me_roots;
-
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
-
- if (object && !object->isAttachment())
- {
- LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot());
- if (root)
- {
- if (me_roots.find(root) == me_roots.end())
- {
- me_roots.insert(root);
- cost += root->getLinksetCost();
- }
- }
- }
- }
-
- return cost;
-}
-
-F32 LLObjectSelection::getSelectedPhysicsCost()
-{
- cleanupNodes();
- F32 cost = 0.f;
-
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
-
- if (object)
- {
- cost += object->getPhysicsCost();
- }
- }
-
- return cost;
-}
-
-F32 LLObjectSelection::getSelectedLinksetPhysicsCost()
-{
- cleanupNodes();
- F32 cost = 0.f;
-
- std::set<LLViewerObject*> me_roots;
-
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
-
- if (object)
- {
- LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot());
- if (root)
- {
- if (me_roots.find(root) == me_roots.end())
- {
- me_roots.insert(root);
- cost += root->getLinksetPhysicsCost();
- }
- }
- }
- }
-
- return cost;
-}
-
-F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* visible_bytes)
-{
- F32 cost = 0.f;
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
-
- if (object)
- {
- cost += object->getStreamingCost();
-
- S32 bytes = 0;
- S32 visible = 0;
- LLMeshCostData costs;
- if (object->getCostData(costs))
- {
- bytes = costs.getSizeTotal();
- visible = costs.getSizeByLOD(object->getLOD());
- }
- if (total_bytes)
- {
- *total_bytes += bytes;
- }
-
- if (visible_bytes)
- {
- *visible_bytes += visible;
- }
- }
- }
-
- return cost;
-}
-
-U32 LLObjectSelection::getSelectedObjectTriangleCount(S32* vcount)
-{
- U32 count = 0;
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
-
- if (object)
- {
- S32 vt = 0;
- count += object->getTriangleCount(&vt);
- *vcount += vt;
- }
- }
-
- return count;
-}
-
-S32 LLObjectSelection::getSelectedObjectRenderCost()
-{
- S32 cost = 0;
- LLVOVolume::texture_cost_t textures;
- typedef std::set<LLUUID> uuid_list_t;
- uuid_list_t computed_objects;
-
- typedef std::list<LLPointer<LLViewerObject> > child_list_t;
- typedef const child_list_t const_child_list_t;
-
- // add render cost of complete linksets first, to get accurate texture counts
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
-
- LLVOVolume* object = (LLVOVolume*)node->getObject();
-
- if (object && object->isRootEdit())
- {
- cost += object->getRenderCost(textures);
- computed_objects.insert(object->getID());
-
- const_child_list_t children = object->getChildren();
- for (const_child_list_t::const_iterator child_iter = children.begin();
- child_iter != children.end();
- ++child_iter)
- {
- LLViewerObject* child_obj = *child_iter;
- LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
- if (child)
- {
- cost += child->getRenderCost(textures);
- computed_objects.insert(child->getID());
- }
- }
-
- for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
- {
- // add the cost of each individual texture in the linkset
- cost += LLVOVolume::getTextureCost(*iter);
- }
-
- textures.clear();
- }
- }
-
- // add any partial linkset objects, texture cost may be slightly misleading
- for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
- {
- LLSelectNode* node = *iter;
- LLVOVolume* object = (LLVOVolume*)node->getObject();
-
- if (object && computed_objects.find(object->getID()) == computed_objects.end() )
- {
- cost += object->getRenderCost(textures);
- computed_objects.insert(object->getID());
- }
-
- for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
- {
- // add the cost of each individual texture in the linkset
- cost += LLVOVolume::getTextureCost(*iter);
- }
-
- textures.clear();
- }
-
- return cost;
-}
-
-//-----------------------------------------------------------------------------
-// getTECount()
-//-----------------------------------------------------------------------------
-S32 LLObjectSelection::getTECount()
-{
- S32 count = 0;
- for (LLObjectSelection::iterator iter = begin(); iter != end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if (!object)
- continue;
- S32 num_tes = object->getNumTEs();
- for (S32 te = 0; te < num_tes; te++)
- {
- if (node->isTESelected(te))
- {
- ++count;
- }
- }
- }
- return count;
-}
-
-//-----------------------------------------------------------------------------
-// getRootObjectCount()
-//-----------------------------------------------------------------------------
-S32 LLObjectSelection::getRootObjectCount()
-{
- S32 count = 0;
- for (LLObjectSelection::root_iterator iter = root_begin(); iter != root_end(); iter++)
- {
- ++count;
- }
- return count;
-}
-
-bool LLObjectSelection::applyToObjects(LLSelectedObjectFunctor* func)
-{
- bool result = true;
- for (iterator iter = begin(); iter != end(); )
- {
- iterator nextiter = iter++;
- LLViewerObject* object = (*nextiter)->getObject();
- if (!object)
- continue;
- bool r = func->apply(object);
- result = result && r;
- }
- return result;
-}
-
-bool LLObjectSelection::checkAnimatedObjectEstTris()
-{
- F32 est_tris = 0;
- F32 max_tris = 0;
- S32 anim_count = 0;
- for (root_iterator iter = root_begin(); iter != root_end(); ++iter)
- {
- LLViewerObject* object = (*iter)->getObject();
- if (!object)
- continue;
- if (object->isAnimatedObject())
- {
- anim_count++;
- }
- est_tris += object->recursiveGetEstTrianglesMax();
- max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris());
- }
- return anim_count==0 || est_tris <= max_tris;
-}
-
-bool LLObjectSelection::checkAnimatedObjectLinkable()
-{
- return checkAnimatedObjectEstTris();
-}
-
-bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly)
-{
- bool result = !firstonly;
- for (root_iterator iter = root_begin(); iter != root_end(); )
- {
- root_iterator nextiter = iter++;
- LLViewerObject* object = (*nextiter)->getObject();
- if (!object)
- continue;
- bool r = func->apply(object);
- if (firstonly && r)
- return true;
- else
- result = result && r;
- }
- return result;
-}
-
-bool LLObjectSelection::applyToTEs(LLSelectedTEFunctor* func, bool firstonly)
-{
- bool result = !firstonly;
- for (iterator iter = begin(); iter != end(); )
- {
- iterator nextiter = iter++;
- LLSelectNode* node = *nextiter;
- LLViewerObject* object = (*nextiter)->getObject();
- if (!object)
- continue;
- S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); // avatars have TEs but no faces
- for (S32 te = 0; te < num_tes; ++te)
- {
- if (node->isTESelected(te))
- {
- bool r = func->apply(object, te);
- if (firstonly && r)
- return true;
- else
- result = result && r;
- }
- }
- }
- return result;
-}
-
-bool LLObjectSelection::applyToNodes(LLSelectedNodeFunctor *func, bool firstonly)
-{
- bool result = !firstonly;
- for (iterator iter = begin(); iter != end(); )
- {
- iterator nextiter = iter++;
- LLSelectNode* node = *nextiter;
- bool r = func->apply(node);
- if (firstonly && r)
- return true;
- else
- result = result && r;
- }
- return result;
-}
-
-bool LLObjectSelection::applyToRootNodes(LLSelectedNodeFunctor *func, bool firstonly)
-{
- bool result = !firstonly;
- for (root_iterator iter = root_begin(); iter != root_end(); )
- {
- root_iterator nextiter = iter++;
- LLSelectNode* node = *nextiter;
- bool r = func->apply(node);
- if (firstonly && r)
- return true;
- else
- result = result && r;
- }
- return result;
-}
-
-bool LLObjectSelection::isMultipleTESelected()
-{
- bool te_selected = false;
- // ...all faces
- for (LLObjectSelection::iterator iter = begin();
- iter != end(); iter++)
- {
- LLSelectNode* nodep = *iter;
- for (S32 i = 0; i < SELECT_MAX_TES; i++)
- {
- if(nodep->isTESelected(i))
- {
- if(te_selected)
- {
- return true;
- }
- te_selected = true;
- }
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// contains()
-//-----------------------------------------------------------------------------
-bool LLObjectSelection::contains(LLViewerObject* object)
-{
- return findNode(object) != NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// contains()
-//-----------------------------------------------------------------------------
-bool LLObjectSelection::contains(LLViewerObject* object, S32 te)
-{
- if (te == SELECT_ALL_TES)
- {
- // ...all faces
- for (LLObjectSelection::iterator iter = begin();
- iter != end(); iter++)
- {
- LLSelectNode* nodep = *iter;
- if (nodep->getObject() == object)
- {
- // Optimization
- if (nodep->getTESelectMask() == TE_SELECT_MASK_ALL)
- {
- return true;
- }
-
- bool all_selected = true;
- for (S32 i = 0; i < object->getNumTEs(); i++)
- {
- all_selected = all_selected && nodep->isTESelected(i);
- }
- return all_selected;
- }
- }
- return false;
- }
- else
- {
- // ...one face
- for (LLObjectSelection::iterator iter = begin(); iter != end(); iter++)
- {
- LLSelectNode* nodep = *iter;
- if (nodep->getObject() == object && nodep->isTESelected(te))
- {
- return true;
- }
- }
- return false;
- }
-}
-
-// returns true is any node is currenly worn as an attachment
-bool LLObjectSelection::isAttachment()
-{
- return (mSelectType == SELECT_TYPE_ATTACHMENT || mSelectType == SELECT_TYPE_HUD);
-}
-
-//-----------------------------------------------------------------------------
-// getSelectedParentObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* getSelectedParentObject(LLViewerObject *object)
-{
- LLViewerObject *parent;
- while (object && (parent = (LLViewerObject*)object->getParent()))
- {
- if (parent->isSelected())
- {
- object = parent;
- }
- else
- {
- break;
- }
- }
- return object;
-}
-
-//-----------------------------------------------------------------------------
-// getFirstNode
-//-----------------------------------------------------------------------------
-LLSelectNode* LLObjectSelection::getFirstNode(LLSelectedNodeFunctor* func)
-{
- for (iterator iter = begin(); iter != end(); ++iter)
- {
- LLSelectNode* node = *iter;
- if (func == NULL || func->apply(node))
- {
- return node;
- }
- }
- return NULL;
-}
-
-LLSelectNode* LLObjectSelection::getFirstRootNode(LLSelectedNodeFunctor* func, bool non_root_ok)
-{
- for (root_iterator iter = root_begin(); iter != root_end(); ++iter)
- {
- LLSelectNode* node = *iter;
- if (func == NULL || func->apply(node))
- {
- return node;
- }
- }
- if (non_root_ok)
- {
- // Get non root
- return getFirstNode(func);
- }
- return NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// getFirstSelectedObject
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstSelectedObject(LLSelectedNodeFunctor* func, bool get_parent)
-{
- LLSelectNode* res = getFirstNode(func);
- if (res && get_parent)
- {
- return getSelectedParentObject(res->getObject());
- }
- else if (res)
- {
- return res->getObject();
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getFirstObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstObject()
-{
- LLSelectNode* res = getFirstNode(NULL);
- return res ? res->getObject() : NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getFirstRootObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstRootObject(bool non_root_ok)
-{
- LLSelectNode* res = getFirstRootNode(NULL, non_root_ok);
- return res ? res->getObject() : NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getFirstMoveableNode()
-//-----------------------------------------------------------------------------
-LLSelectNode* LLObjectSelection::getFirstMoveableNode(bool get_root_first)
-{
- struct f : public LLSelectedNodeFunctor
- {
- bool apply(LLSelectNode* node)
- {
- LLViewerObject* obj = node->getObject();
- return obj && obj->permMove() && !obj->isPermanentEnforced();
- }
- } func;
- LLSelectNode* res = get_root_first ? getFirstRootNode(&func, true) : getFirstNode(&func);
- return res;
-}
-
-//-----------------------------------------------------------------------------
-// getFirstCopyableObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstCopyableObject(bool get_parent)
-{
- struct f : public LLSelectedNodeFunctor
- {
- bool apply(LLSelectNode* node)
- {
- LLViewerObject* obj = node->getObject();
- return obj && obj->permCopy() && !obj->isAttachment();
- }
- } func;
- return getFirstSelectedObject(&func, get_parent);
-}
-
-//-----------------------------------------------------------------------------
-// getFirstDeleteableObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstDeleteableObject()
-{
- //RN: don't currently support deletion of child objects, as that requires separating them first
- // then derezzing to trash
-
- struct f : public LLSelectedNodeFunctor
- {
- bool apply(LLSelectNode* node)
- {
- LLViewerObject* obj = node->getObject();
- // you can delete an object if you are the owner
- // or you have permission to modify it.
- if( obj && !obj->isPermanentEnforced() &&
- ( (obj->permModify()) ||
- (obj->permYouOwner()) ||
- (!obj->permAnyOwner()) )) // public
- {
- if( !obj->isAttachment() )
- {
- return true;
- }
- }
- return false;
- }
- } func;
- LLSelectNode* node = getFirstNode(&func);
- return node ? node->getObject() : NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getFirstEditableObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstEditableObject(bool get_parent)
-{
- struct f : public LLSelectedNodeFunctor
- {
- bool apply(LLSelectNode* node)
- {
- LLViewerObject* obj = node->getObject();
- return obj && obj->permModify();
- }
- } func;
- return getFirstSelectedObject(&func, get_parent);
-}
-
-//-----------------------------------------------------------------------------
-// getFirstMoveableObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstMoveableObject(bool get_parent)
-{
- struct f : public LLSelectedNodeFunctor
- {
- bool apply(LLSelectNode* node)
- {
- LLViewerObject* obj = node->getObject();
- return obj && obj->permMove() && !obj->isPermanentEnforced();
- }
- } func;
- return getFirstSelectedObject(&func, get_parent);
-}
-
-//-----------------------------------------------------------------------------
-// getFirstUndoEnabledObject()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLObjectSelection::getFirstUndoEnabledObject(bool get_parent)
-{
- struct f : public LLSelectedNodeFunctor
- {
- bool apply(LLSelectNode* node)
- {
- LLViewerObject* obj = node->getObject();
- return obj && (obj->permModify() || (obj->permMove() && !obj->isPermanentEnforced()));
- }
- } func;
- return getFirstSelectedObject(&func, get_parent);
-}
-
-//-----------------------------------------------------------------------------
-// Position + Rotation update methods called from LLViewerJoystick
-//-----------------------------------------------------------------------------
-bool LLSelectMgr::selectionMove(const LLVector3& displ,
- F32 roll, F32 pitch, F32 yaw, U32 update_type)
-{
- if (update_type == UPD_NONE)
- {
- return false;
- }
-
- LLVector3 displ_global;
- bool update_success = true;
- bool update_position = update_type & UPD_POSITION;
- bool update_rotation = update_type & UPD_ROTATION;
- const bool noedit_linked_parts = !gSavedSettings.getBOOL("EditLinkedParts");
-
- if (update_position)
- {
- // calculate the distance of the object closest to the camera origin
- F32 min_dist_squared = F32_MAX; // value will be overridden in the loop
-
- LLVector3 obj_pos;
- for (LLObjectSelection::root_iterator it = getSelection()->root_begin();
- it != getSelection()->root_end(); ++it)
- {
- obj_pos = (*it)->getObject()->getPositionEdit();
-
- F32 obj_dist_squared = dist_vec_squared(obj_pos, LLViewerCamera::getInstance()->getOrigin());
- if (obj_dist_squared < min_dist_squared)
- {
- min_dist_squared = obj_dist_squared;
- }
- }
-
- // factor the distance into the displacement vector. This will get us
- // equally visible movements for both close and far away selections.
- F32 min_dist = sqrt((F32) sqrtf(min_dist_squared)) / 2;
- displ_global.setVec(displ.mV[0] * min_dist,
- displ.mV[1] * min_dist,
- displ.mV[2] * min_dist);
-
- // equates to: Displ_global = Displ * M_cam_axes_in_global_frame
- displ_global = LLViewerCamera::getInstance()->rotateToAbsolute(displ_global);
- }
-
- LLQuaternion new_rot;
- if (update_rotation)
- {
- // let's calculate the rotation around each camera axes
- LLQuaternion qx(roll, LLViewerCamera::getInstance()->getAtAxis());
- LLQuaternion qy(pitch, LLViewerCamera::getInstance()->getLeftAxis());
- LLQuaternion qz(yaw, LLViewerCamera::getInstance()->getUpAxis());
- new_rot.setQuat(qx * qy * qz);
- }
-
- LLViewerObject *obj;
- S32 obj_count = getSelection()->getObjectCount();
- for (LLObjectSelection::root_iterator it = getSelection()->root_begin();
- it != getSelection()->root_end(); ++it )
- {
- obj = (*it)->getObject();
- bool enable_pos = false, enable_rot = false;
- bool perm_move = obj->permMove() && !obj->isPermanentEnforced();
- bool perm_mod = obj->permModify();
-
- LLVector3d sel_center(getSelectionCenterGlobal());
-
- if (update_rotation)
- {
- enable_rot = perm_move
- && ((perm_mod && !obj->isAttachment()) || noedit_linked_parts);
-
- if (enable_rot)
- {
- int children_count = obj->getChildren().size();
- if (obj_count > 1 && children_count > 0)
- {
- // for linked sets, rotate around the group center
- const LLVector3 t(obj->getPositionGlobal() - sel_center);
-
- // Ra = T x R x T^-1
- LLMatrix4 mt; mt.setTranslation(t);
- const LLMatrix4 mnew_rot(new_rot);
- LLMatrix4 mt_1; mt_1.setTranslation(-t);
- mt *= mnew_rot;
- mt *= mt_1;
-
- // Rfin = Rcur * Ra
- obj->setRotation(obj->getRotationEdit() * mt.quaternion());
- displ_global += mt.getTranslation();
- }
- else
- {
- obj->setRotation(obj->getRotationEdit() * new_rot);
- }
- }
- else
- {
- update_success = false;
- }
- }
-
- if (update_position)
- {
- // establish if object can be moved or not
- enable_pos = perm_move && !obj->isAttachment()
- && (perm_mod || noedit_linked_parts);
-
- if (enable_pos)
- {
- obj->setPosition(obj->getPositionEdit() + displ_global);
- }
- else
- {
- update_success = false;
- }
- }
-
- if (enable_pos && enable_rot && obj->mDrawable.notNull())
- {
- gPipeline.markMoved(obj->mDrawable, true);
- }
- }
-
- if (update_position && update_success && obj_count > 1)
- {
- updateSelectionCenter();
- }
-
- return update_success;
-}
-
-void LLSelectMgr::sendSelectionMove()
-{
- LLSelectNode *node = mSelectedObjects->getFirstRootNode();
- if (node == NULL)
- {
- return;
- }
-
- //saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
-
- U32 update_type = UPD_POSITION | UPD_ROTATION;
- LLViewerRegion *last_region, *curr_region = node->getObject()->getRegion();
- S32 objects_in_this_packet = 0;
-
- // apply to linked objects if unable to select their individual parts
- if (!gSavedSettings.getBOOL("EditLinkedParts") && !getTEMode())
- {
- // tell simulator to apply to whole linked sets
- update_type |= UPD_LINKED_SETS;
- }
-
- // prepare first bulk message
- gMessageSystem->newMessage("MultipleObjectUpdate");
- packAgentAndSessionID(&update_type);
-
- LLViewerObject *obj = NULL;
- for (LLObjectSelection::root_iterator it = getSelection()->root_begin();
- it != getSelection()->root_end(); ++it)
- {
- obj = (*it)->getObject();
-
- // note: following code adapted from sendListToRegions() (@3924)
- last_region = curr_region;
- curr_region = obj->getRegion();
-
- // if not simulator or message too big
- if (curr_region != last_region
- || gMessageSystem->isSendFull(NULL)
- || objects_in_this_packet >= MAX_OBJECTS_PER_PACKET)
- {
- // send sim the current message and start new one
- gMessageSystem->sendReliable(last_region->getHost());
- objects_in_this_packet = 0;
- gMessageSystem->newMessage("MultipleObjectUpdate");
- packAgentAndSessionID(&update_type);
- }
-
- // add another instance of the body of data
- packMultipleUpdate(*it, &update_type);
- ++objects_in_this_packet;
- }
-
- // flush remaining messages
- if (gMessageSystem->getCurrentSendTotal() > 0)
- {
- gMessageSystem->sendReliable(curr_region->getHost());
- }
- else
- {
- gMessageSystem->clearMessage();
- }
-
- //saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
-}
-
-template<>
-bool LLCheckIdenticalFunctor<F32>::same(const F32& a, const F32& b, const F32& tolerance)
-{
- F32 delta = (a - b);
- F32 abs_delta = fabs(delta);
- return abs_delta <= tolerance;
-}
-
-#define DEF_DUMMY_CHECK_FUNCTOR(T) \
-template<> \
-bool LLCheckIdenticalFunctor<T>::same(const T& a, const T& b, const T& tolerance) \
-{ \
- (void)tolerance; \
- return a == b; \
-}
-
-DEF_DUMMY_CHECK_FUNCTOR(LLUUID)
-DEF_DUMMY_CHECK_FUNCTOR(LLGLenum)
-DEF_DUMMY_CHECK_FUNCTOR(LLTextureEntry)
-DEF_DUMMY_CHECK_FUNCTOR(LLTextureEntry::e_texgen)
-DEF_DUMMY_CHECK_FUNCTOR(bool)
-DEF_DUMMY_CHECK_FUNCTOR(U8)
-DEF_DUMMY_CHECK_FUNCTOR(int)
-DEF_DUMMY_CHECK_FUNCTOR(LLColor4)
-DEF_DUMMY_CHECK_FUNCTOR(LLMediaEntry)
-DEF_DUMMY_CHECK_FUNCTOR(LLPointer<LLMaterial>)
-DEF_DUMMY_CHECK_FUNCTOR(LLPointer<LLGLTFMaterial>)
-DEF_DUMMY_CHECK_FUNCTOR(std::string)
-DEF_DUMMY_CHECK_FUNCTOR(std::vector<std::string>)
-
-template<>
-bool LLCheckIdenticalFunctor<class LLFace *>::same(class LLFace* const & a, class LLFace* const & b, class LLFace* const & tolerance) \
-{ \
- (void)tolerance; \
- return a == b; \
-}
-
+/** + * @file llselectmgr.cpp + * @brief A manager for selected objects and faces. + * + * $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 +#define LLSELECTMGR_CPP +#include "llselectmgr.h" +#include "llmaterialmgr.h" + +// library includes +#include "llcachename.h" +#include "llavatarnamecache.h" +#include "lldbstrings.h" +#include "llgl.h" +#include "llmediaentry.h" +#include "llrender.h" +#include "llnotifications.h" +#include "llpermissions.h" +#include "llpermissionsflags.h" +#include "lltrans.h" +#include "llundo.h" +#include "lluuid.h" +#include "llvolume.h" +#include "llcontrolavatar.h" +#include "message.h" +#include "object_flags.h" +#include "llquaternion.h" + +// viewer includes +#include "llagent.h" +#include "llagentcamera.h" +#include "llattachmentsmgr.h" +#include "llviewerwindow.h" +#include "lldrawable.h" +#include "llfloaterinspect.h" +#include "llfloaterreporter.h" +#include "llfloaterreg.h" +#include "llfloatertools.h" +#include "llframetimer.h" +#include "llfocusmgr.h" +#include "llgltfmateriallist.h" +#include "llhudeffecttrail.h" +#include "llhudmanager.h" +#include "llinventorymodel.h" +#include "llmenugl.h" +#include "llmeshrepository.h" +#include "llmutelist.h" +#include "llnotificationsutil.h" +#include "llsidepaneltaskinfo.h" +#include "llslurl.h" +#include "llstatusbar.h" +#include "llsurface.h" +#include "lltool.h" +#include "lltooldraganddrop.h" +#include "lltoolmgr.h" +#include "lltoolpie.h" +#include "llui.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewertexturelist.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llviewermenu.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llvoavatarself.h" +#include "llvovolume.h" +#include "pipeline.h" +#include "llviewershadermgr.h" +#include "llpanelface.h" +#include "llglheaders.h" +#include "llinventoryobserver.h" + +LLViewerObject* getSelectedParentObject(LLViewerObject *object) ; +// +// Consts +// + +const F32 SILHOUETTE_UPDATE_THRESHOLD_SQUARED = 0.02f; +const S32 MAX_SILS_PER_FRAME = 50; +const S32 MAX_OBJECTS_PER_PACKET = 254; +// For linked sets +const S32 MAX_CHILDREN_PER_TASK = 255; + +// +// Globals +// + +//bool gDebugSelectMgr = false; + +//bool gHideSelectedObjects = false; +//bool gAllowSelectAvatar = false; + +bool LLSelectMgr::sRectSelectInclusive = true; +bool LLSelectMgr::sRenderHiddenSelections = true; +bool LLSelectMgr::sRenderLightRadius = false; +F32 LLSelectMgr::sHighlightThickness = 0.f; +F32 LLSelectMgr::sHighlightUScale = 0.f; +F32 LLSelectMgr::sHighlightVScale = 0.f; +F32 LLSelectMgr::sHighlightAlpha = 0.f; +F32 LLSelectMgr::sHighlightAlphaTest = 0.f; +F32 LLSelectMgr::sHighlightUAnim = 0.f; +F32 LLSelectMgr::sHighlightVAnim = 0.f; +LLColor4 LLSelectMgr::sSilhouetteParentColor; +LLColor4 LLSelectMgr::sSilhouetteChildColor; +LLColor4 LLSelectMgr::sHighlightInspectColor; +LLColor4 LLSelectMgr::sHighlightParentColor; +LLColor4 LLSelectMgr::sHighlightChildColor; +LLColor4 LLSelectMgr::sContextSilhouetteColor; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// struct LLDeRezInfo +// +// Used to keep track of important derez info. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +struct LLDeRezInfo +{ + EDeRezDestination mDestination; + LLUUID mDestinationID; + LLDeRezInfo(EDeRezDestination dest, const LLUUID& dest_id) : + mDestination(dest), mDestinationID(dest_id) {} +}; + +// +// Imports +// + +//----------------------------------------------------------------------------- +// ~LLSelectionCallbackData() +//----------------------------------------------------------------------------- + +LLSelectionCallbackData::LLSelectionCallbackData() +{ + LLSelectMgr *instance = LLSelectMgr::getInstance(); + LLObjectSelectionHandle selection = instance->getSelection(); + if (!selection->getNumNodes()) + { + return; + } + mSelectedObjects = new LLObjectSelection(); + + for (LLObjectSelection::iterator iter = selection->begin(); + iter != selection->end();) + { + LLObjectSelection::iterator curiter = iter++; + + LLSelectNode *nodep = *curiter; + LLViewerObject* objectp = nodep->getObject(); + + if (!objectp) + { + mSelectedObjects->mSelectType = SELECT_TYPE_WORLD; + } + else + { + LLSelectNode* new_nodep = new LLSelectNode(*nodep); + mSelectedObjects->addNode(new_nodep); + + if (objectp->isHUDAttachment()) + { + mSelectedObjects->mSelectType = SELECT_TYPE_HUD; + } + else if (objectp->isAttachment()) + { + mSelectedObjects->mSelectType = SELECT_TYPE_ATTACHMENT; + } + else + { + mSelectedObjects->mSelectType = SELECT_TYPE_WORLD; + } + } + } +} + + +// +// Functions +// + +void LLSelectMgr::cleanupGlobals() +{ + LLSelectMgr::getInstance()->clearSelections(); +} + +//----------------------------------------------------------------------------- +// LLSelectMgr() +//----------------------------------------------------------------------------- +LLSelectMgr::LLSelectMgr() + : mHideSelectedObjects(LLCachedControl<bool>(gSavedSettings, "HideSelectedObjects", false)), + mRenderHighlightSelections(LLCachedControl<bool>(gSavedSettings, "RenderHighlightSelections", true)), + mAllowSelectAvatar( LLCachedControl<bool>(gSavedSettings, "AllowSelectAvatar", false)), + mDebugSelectMgr(LLCachedControl<bool>(gSavedSettings, "DebugSelectMgr", false)) +{ + mTEMode = false; + mTextureChannel = LLRender::DIFFUSE_MAP; + mLastCameraPos.clearVec(); + + sHighlightThickness = gSavedSettings.getF32("SelectionHighlightThickness"); + sHighlightUScale = gSavedSettings.getF32("SelectionHighlightUScale"); + sHighlightVScale = gSavedSettings.getF32("SelectionHighlightVScale"); + sHighlightAlpha = gSavedSettings.getF32("SelectionHighlightAlpha") * 2; + sHighlightAlphaTest = gSavedSettings.getF32("SelectionHighlightAlphaTest"); + sHighlightUAnim = gSavedSettings.getF32("SelectionHighlightUAnim"); + sHighlightVAnim = gSavedSettings.getF32("SelectionHighlightVAnim"); + + sSilhouetteParentColor =LLUIColorTable::instance().getColor("SilhouetteParentColor"); + sSilhouetteChildColor = LLUIColorTable::instance().getColor("SilhouetteChildColor"); + sHighlightParentColor = LLUIColorTable::instance().getColor("HighlightParentColor"); + sHighlightChildColor = LLUIColorTable::instance().getColor("HighlightChildColor"); + sHighlightInspectColor = LLUIColorTable::instance().getColor("HighlightInspectColor"); + sContextSilhouetteColor = LLUIColorTable::instance().getColor("ContextSilhouetteColor")*0.5f; + + sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); + + mRenderSilhouettes = true; + + mGridMode = GRID_MODE_WORLD; + gSavedSettings.setS32("GridMode", (S32)GRID_MODE_WORLD); + + mSelectedObjects = new LLObjectSelection(); + mHoverObjects = new LLObjectSelection(); + mHighlightedObjects = new LLObjectSelection(); + + mForceSelection = false; + mShowSelection = false; +} + + +//----------------------------------------------------------------------------- +// ~LLSelectMgr() +//----------------------------------------------------------------------------- +LLSelectMgr::~LLSelectMgr() +{ + clearSelections(); +} + +void LLSelectMgr::clearSelections() +{ + mHoverObjects->deleteAllNodes(); + mSelectedObjects->deleteAllNodes(); + mHighlightedObjects->deleteAllNodes(); + mRectSelectedObjects.clear(); + mGridObjects.deleteAllNodes(); + + LLPipeline::setRenderHighlightTextureChannel(LLRender::DIFFUSE_MAP); +} + +void LLSelectMgr::update() +{ + mSelectedObjects->cleanupNodes(); +} + +void LLSelectMgr::updateEffects() +{ + //keep reference grid objects active + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + LLDrawable* drawable = object->mDrawable; + if (drawable) + { + gPipeline.markMoved(drawable); + } + return true; + } + } func; + mGridObjects.applyToObjects(&func); + + if (mEffectsTimer.getElapsedTimeF32() > 1.f) + { + mSelectedObjects->updateEffects(); + mEffectsTimer.reset(); + } +} + +void LLSelectMgr::resetObjectOverrides() +{ + resetObjectOverrides(getSelection()); +} + +void LLSelectMgr::resetObjectOverrides(LLObjectSelectionHandle selected_handle) +{ + struct f : public LLSelectedNodeFunctor + { + f(bool a, LLSelectMgr* p) : mAvatarOverridesPersist(a), mManager(p) {} + bool mAvatarOverridesPersist; + LLSelectMgr* mManager; + virtual bool apply(LLSelectNode* node) + { + if (mAvatarOverridesPersist) + { + LLViewerObject* object = node->getObject(); + if (object && !object->getParent()) + { + LLVOAvatar* avatar = object->asAvatar(); + if (avatar) + { + mManager->mAvatarOverridesMap.emplace(avatar->getID(), AvatarPositionOverride(node->mLastPositionLocal, node->mLastRotation, object)); + } + } + } + node->mLastPositionLocal.setVec(0, 0, 0); + node->mLastRotation = LLQuaternion(); + node->mLastScale.setVec(0, 0, 0); + return true; + } + } func(mAllowSelectAvatar, this); + + selected_handle->applyToNodes(&func); +} + +void LLSelectMgr::overrideObjectUpdates() +{ + //override any position updates from simulator on objects being edited + struct f : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* selectNode) + { + LLViewerObject* object = selectNode->getObject(); + if (object && object->permMove() && !object->isPermanentEnforced()) + { + if (!selectNode->mLastPositionLocal.isExactlyZero()) + { + object->setPosition(selectNode->mLastPositionLocal); + } + if (selectNode->mLastRotation != LLQuaternion()) + { + object->setRotation(selectNode->mLastRotation); + } + if (!selectNode->mLastScale.isExactlyZero()) + { + object->setScale(selectNode->mLastScale); + } + } + return true; + } + } func; + getSelection()->applyToNodes(&func); +} + +void LLSelectMgr::resetAvatarOverrides() +{ + mAvatarOverridesMap.clear(); +} + +void LLSelectMgr::overrideAvatarUpdates() +{ + if (mAvatarOverridesMap.size() == 0) + { + return; + } + + if (!mAllowSelectAvatar || !gFloaterTools) + { + resetAvatarOverrides(); + return; + } + + if (!gFloaterTools->getVisible() && getSelection()->isEmpty()) + { + // when user switches selection, floater is invisible and selection is empty + LLToolset *toolset = LLToolMgr::getInstance()->getCurrentToolset(); + if (toolset->isShowFloaterTools() + && toolset->isToolSelected(0)) // Pie tool + { + resetAvatarOverrides(); + return; + } + } + + // remove selected avatars from this list, + // but set object overrides to make sure avatar won't snap back + struct f : public LLSelectedNodeFunctor + { + f(LLSelectMgr* p) : mManager(p) {} + LLSelectMgr* mManager; + virtual bool apply(LLSelectNode* selectNode) + { + LLViewerObject* object = selectNode->getObject(); + if (object && !object->getParent()) + { + LLVOAvatar* avatar = object->asAvatar(); + if (avatar) + { + uuid_av_override_map_t::iterator iter = mManager->mAvatarOverridesMap.find(avatar->getID()); + if (iter != mManager->mAvatarOverridesMap.end()) + { + if (selectNode->mLastPositionLocal.isExactlyZero()) + { + selectNode->mLastPositionLocal = iter->second.mLastPositionLocal; + } + if (selectNode->mLastRotation == LLQuaternion()) + { + selectNode->mLastRotation = iter->second.mLastRotation; + } + mManager->mAvatarOverridesMap.erase(iter); + } + } + } + return true; + } + } func(this); + getSelection()->applyToNodes(&func); + + // Override avatar positions + uuid_av_override_map_t::iterator it = mAvatarOverridesMap.begin(); + while (it != mAvatarOverridesMap.end()) + { + if (it->second.mObject->isDead()) + { + it = mAvatarOverridesMap.erase(it); + } + else + { + if (!it->second.mLastPositionLocal.isExactlyZero()) + { + it->second.mObject->setPosition(it->second.mLastPositionLocal); + } + if (it->second.mLastRotation != LLQuaternion()) + { + it->second.mObject->setRotation(it->second.mLastRotation); + } + it++; + } + } +} + +//----------------------------------------------------------------------------- +// Select just the object, not any other group members. +//----------------------------------------------------------------------------- +LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face) +{ + llassert( object ); + + //remember primary object + mSelectedObjects->mPrimaryObject = object; + + // Don't add an object that is already in the list + if (object->isSelected() ) { + // make sure point at position is updated + updatePointAt(); + gEditMenuHandler = this; + return NULL; + } + + if (!canSelectObject(object)) + { + //make_ui_sound("UISndInvalidOp"); + return NULL; + } + + // LL_INFOS() << "Adding object to selected object list" << LL_ENDL; + + // Place it in the list and tag it. + // This will refresh dialogs. + addAsIndividual(object, face); + + // Stop the object from moving (this anticipates changes on the + // simulator in LLTask::userSelect) + // *FIX: shouldn't zero out these either + object->setVelocity(LLVector3::zero); + object->setAcceleration(LLVector3::zero); + //object->setAngularVelocity(LLVector3::zero); + object->resetRot(); + + // Always send to simulator, so you get a copy of the + // permissions structure back. + gMessageSystem->newMessageFast(_PREHASH_ObjectSelect); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() ); + LLViewerRegion* regionp = object->getRegion(); + gMessageSystem->sendReliable( regionp->getHost()); + + updatePointAt(); + updateSelectionCenter(); + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + + // have selection manager handle edit menu immediately after + // user selects an object + if (mSelectedObjects->getObjectCount()) + { + gEditMenuHandler = this; + } + + return mSelectedObjects; +} + +//----------------------------------------------------------------------------- +// Select the object, parents and children. +//----------------------------------------------------------------------------- +LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, bool add_to_end, bool ignore_select_owned) +{ + llassert( obj ); + + //remember primary object + mSelectedObjects->mPrimaryObject = obj; + + // This may be incorrect if things weren't family selected before... - djs 07/08/02 + // Don't add an object that is already in the list + if (obj->isSelected() ) + { + // make sure pointat position is updated + updatePointAt(); + gEditMenuHandler = this; + return NULL; + } + + if (!canSelectObject(obj,ignore_select_owned)) + { + //make_ui_sound("UISndInvalidOp"); + return NULL; + } + + // Since we're selecting a family, start at the root, but + // don't include an avatar. + LLViewerObject* root = obj; + + while(!root->isAvatar() && root->getParent()) + { + LLViewerObject* parent = (LLViewerObject*)root->getParent(); + if (parent->isAvatar()) + { + break; + } + root = parent; + } + + // Collect all of the objects + std::vector<LLViewerObject*> objects; + + root->addThisAndNonJointChildren(objects); + addAsFamily(objects, add_to_end); + + updateSelectionCenter(); + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + updatePointAt(); + + dialog_refresh_all(); + + // Always send to simulator, so you get a copy of the permissions + // structure back. + sendSelect(); + + // Stop the object from moving (this anticipates changes on the + // simulator in LLTask::userSelect) + root->setVelocity(LLVector3::zero); + root->setAcceleration(LLVector3::zero); + //root->setAngularVelocity(LLVector3::zero); + root->resetRot(); + + // leave component mode + if (gSavedSettings.getBOOL("EditLinkedParts")) + { + gSavedSettings.setBOOL("EditLinkedParts", false); + promoteSelectionToRoot(); + } + + // have selection manager handle edit menu immediately after + // user selects an object + if (mSelectedObjects->getObjectCount()) + { + gEditMenuHandler = this; + } + + return mSelectedObjects; +} + +//----------------------------------------------------------------------------- +// Select the object, parents and children. +//----------------------------------------------------------------------------- +LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list, + bool send_to_sim) +{ + // Collect all of the objects, children included + std::vector<LLViewerObject*> objects; + + //clear primary object (no primary object) + mSelectedObjects->mPrimaryObject = NULL; + + if (object_list.size() < 1) + { + return NULL; + } + + // NOTE -- we add the objects in REVERSE ORDER + // to preserve the order in the mSelectedObjects list + for (std::vector<LLViewerObject*>::const_reverse_iterator riter = object_list.rbegin(); + riter != object_list.rend(); ++riter) + { + LLViewerObject *object = *riter; + + llassert( object ); + + if (!canSelectObject(object)) continue; + + object->addThisAndNonJointChildren(objects); + addAsFamily(objects); + + // Stop the object from moving (this anticipates changes on the + // simulator in LLTask::userSelect) + object->setVelocity(LLVector3::zero); + object->setAcceleration(LLVector3::zero); + //object->setAngularVelocity(LLVector3::zero); + object->resetRot(); + } + + updateSelectionCenter(); + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + updatePointAt(); + dialog_refresh_all(); + + // Almost always send to simulator, so you get a copy of the permissions + // structure back. + // JC: The one case where you don't want to do this is if you're selecting + // all the objects on a sim. + if (send_to_sim) + { + sendSelect(); + } + + // leave component mode + if (gSavedSettings.getBOOL("EditLinkedParts")) + { + gSavedSettings.setBOOL("EditLinkedParts", false); + promoteSelectionToRoot(); + } + + // have selection manager handle edit menu immediately after + // user selects an object + if (mSelectedObjects->getObjectCount()) + { + gEditMenuHandler = this; + } + + return mSelectedObjects; +} + +// Use for when the simulator kills an object. This version also +// handles informing the current tool of the object's deletion. +// +// Caller needs to call dialog_refresh_all if necessary. +bool LLSelectMgr::removeObjectFromSelections(const LLUUID &id) +{ + bool object_found = false; + LLTool *tool = NULL; + + tool = LLToolMgr::getInstance()->getCurrentTool(); + + // It's possible that the tool is editing an object that is not selected + LLViewerObject* tool_editing_object = tool->getEditingObject(); + if( tool_editing_object && tool_editing_object->mID == id) + { + tool->stopEditing(); + object_found = true; + } + + // Iterate through selected objects list and kill the object + if( !object_found ) + { + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); ) + { + LLObjectSelection::iterator curiter = iter++; + LLViewerObject* object = (*curiter)->getObject(); + if (object->mID == id) + { + if (tool) + { + tool->stopEditing(); + } + + // lose the selection, don't tell simulator, it knows + deselectObjectAndFamily(object, false); + object_found = true; + break; // must break here, may have removed multiple objects from list + } + else if (object->isAvatar() && object->getParent() && ((LLViewerObject*)object->getParent())->mID == id) + { + // It's possible the item being removed has an avatar sitting on it + // So remove the avatar that is sitting on the object. + deselectObjectAndFamily(object, false); + break; // must break here, may have removed multiple objects from list + } + } + } + + return object_found; +} + +bool LLSelectMgr::linkObjects() +{ + if (!LLSelectMgr::getInstance()->selectGetAllRootsValid()) + { + LLNotificationsUtil::add("UnableToLinkWhileDownloading"); + return true; + } + + S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (object_count > MAX_CHILDREN_PER_TASK + 1) + { + LLSD args; + args["COUNT"] = llformat("%d", object_count); + int max = MAX_CHILDREN_PER_TASK+1; + args["MAX"] = llformat("%d", max); + LLNotificationsUtil::add("UnableToLinkObjects", args); + return true; + } + + if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2) + { + LLNotificationsUtil::add("CannotLinkIncompleteSet"); + return true; + } + + if (!LLSelectMgr::getInstance()->selectGetRootsModify()) + { + LLNotificationsUtil::add("CannotLinkModify"); + return true; + } + + if (!LLSelectMgr::getInstance()->selectGetRootsNonPermanentEnforced()) + { + LLNotificationsUtil::add("CannotLinkPermanent"); + return true; + } + + LLUUID owner_id; + std::string owner_name; + if (!LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name)) + { + // we don't actually care if you're the owner, but novices are + // the most likely to be stumped by this one, so offer the + // easiest and most likely solution. + LLNotificationsUtil::add("CannotLinkDifferentOwners"); + return true; + } + + if (!LLSelectMgr::getInstance()->selectGetSameRegion()) + { + LLNotificationsUtil::add("CannotLinkAcrossRegions"); + return true; + } + + LLSelectMgr::getInstance()->sendLink(); + + return true; +} + +bool LLSelectMgr::unlinkObjects() +{ + S32 min_objects_for_confirm = gSavedSettings.getS32("MinObjectsForUnlinkConfirm"); + S32 unlink_object_count = mSelectedObjects->getObjectCount(); // clears out nodes with NULL objects + if (unlink_object_count >= min_objects_for_confirm + && unlink_object_count > mSelectedObjects->getRootObjectCount()) + { + // total count > root count means that there are childer inside and that there are linksets that will be unlinked + LLNotificationsUtil::add("ConfirmUnlink", LLSD(), LLSD(), boost::bind(&LLSelectMgr::confirmUnlinkObjects, this, _1, _2)); + return true; + } + + LLSelectMgr::getInstance()->sendDelink(); + return true; +} + +void LLSelectMgr::confirmUnlinkObjects(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // if Cancel pressed + if (option == 1) + { + return; + } + + LLSelectMgr::getInstance()->sendDelink(); + return; +} + +// in order to link, all objects must have the same owner, and the +// agent must have the ability to modify all of the objects. However, +// we're not answering that question with this method. The question +// we're answering is: does the user have a reasonable expectation +// that a link operation should work? If so, return true, false +// otherwise. this allows the handle_link method to more finely check +// the selection and give an error message when the uer has a +// reasonable expectation for the link to work, but it will fail. +// +// For animated objects, there's additional check that if the +// selection includes at least one animated object, the total mesh +// triangle count cannot exceed the designated limit. +bool LLSelectMgr::enableLinkObjects() +{ + bool new_value = false; + // check if there are at least 2 objects selected, and that the + // user can modify at least one of the selected objects. + + // in component mode, can't link + if (!gSavedSettings.getBOOL("EditLinkedParts")) + { + if(LLSelectMgr::getInstance()->selectGetAllRootsValid() && LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() >= 2) + { + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + LLViewerObject *root_object = (object == NULL) ? NULL : object->getRootEdit(); + return object->permModify() && !object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced()); + } + } func; + const bool firstonly = true; + new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); + } + } + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) + { + new_value = false; + } + return new_value; +} + +bool LLSelectMgr::enableUnlinkObjects() +{ + LLViewerObject* first_editable_object = LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject(); + LLViewerObject *root_object = (first_editable_object == NULL) ? NULL : first_editable_object->getRootEdit(); + + bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() && + first_editable_object && + !first_editable_object->isAttachment() && !first_editable_object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced()); + + return new_value; +} + +void LLSelectMgr::deselectObjectAndFamily(LLViewerObject* object, bool send_to_sim, bool include_entire_object) +{ + // bail if nothing selected or if object wasn't selected in the first place + if(!object) return; + if(!object->isSelected()) return; + + // Collect all of the objects, and remove them + std::vector<LLViewerObject*> objects; + + if (include_entire_object) + { + // Since we're selecting a family, start at the root, but + // don't include an avatar. + LLViewerObject* root = object; + + while(!root->isAvatar() && root->getParent()) + { + LLViewerObject* parent = (LLViewerObject*)root->getParent(); + if (parent->isAvatar()) + { + break; + } + root = parent; + } + + object = root; + } + else + { + object = (LLViewerObject*)object->getRoot(); + } + + object->addThisAndAllChildren(objects); + remove(objects); + + if (!send_to_sim) return; + + //----------------------------------------------------------- + // Inform simulator of deselection + //----------------------------------------------------------- + LLViewerRegion* regionp = object->getRegion(); + + bool start_new_message = true; + S32 select_count = 0; + + LLMessageSystem* msg = gMessageSystem; + for (U32 i = 0; i < objects.size(); i++) + { + if (start_new_message) + { + msg->newMessageFast(_PREHASH_ObjectDeselect); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + select_count++; + start_new_message = false; + } + + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, (objects[i])->getLocalID()); + select_count++; + + // Zap the angular velocity, as the sim will set it to zero + objects[i]->setAngularVelocity( 0,0,0 ); + objects[i]->setVelocity( 0,0,0 ); + + if(msg->isSendFull(NULL) || select_count >= MAX_OBJECTS_PER_PACKET) + { + msg->sendReliable(regionp->getHost() ); + select_count = 0; + start_new_message = true; + } + } + + if (!start_new_message) + { + msg->sendReliable(regionp->getHost() ); + } + + updatePointAt(); + updateSelectionCenter(); +} + +void LLSelectMgr::deselectObjectOnly(LLViewerObject* object, bool send_to_sim) +{ + // bail if nothing selected or if object wasn't selected in the first place + if (!object) return; + if (!object->isSelected() ) return; + + // Zap the angular velocity, as the sim will set it to zero + object->setAngularVelocity( 0,0,0 ); + object->setVelocity( 0,0,0 ); + + if (send_to_sim) + { + LLViewerRegion* region = object->getRegion(); + gMessageSystem->newMessageFast(_PREHASH_ObjectDeselect); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() ); + gMessageSystem->sendReliable(region->getHost()); + } + + // This will refresh dialogs. + remove( object ); + + updatePointAt(); + updateSelectionCenter(); +} + + +//----------------------------------------------------------------------------- +// addAsFamily +//----------------------------------------------------------------------------- + +void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, bool add_to_end) +{ + for (std::vector<LLViewerObject*>::iterator iter = objects.begin(); + iter != objects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + + // Can't select yourself + if (objectp->mID == gAgentID + && !mAllowSelectAvatar) + { + continue; + } + + if (!objectp->isSelected()) + { + LLSelectNode *nodep = new LLSelectNode(objectp, true); + if (add_to_end) + { + mSelectedObjects->addNodeAtEnd(nodep); + } + else + { + mSelectedObjects->addNode(nodep); + } + objectp->setSelected(true); + + if (objectp->getNumTEs() > 0) + { + nodep->selectAllTEs(true); + objectp->setAllTESelected(true); + } + else + { + // object has no faces, so don't mess with faces + } + } + else + { + // we want this object to be selected for real + // so clear transient flag + LLSelectNode* select_node = mSelectedObjects->findNode(objectp); + if (select_node) + { + select_node->setTransient(false); + } + } + } + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); +} + +//----------------------------------------------------------------------------- +// addAsIndividual() - a single object, face, etc +//----------------------------------------------------------------------------- +void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, bool undoable) +{ + // check to see if object is already in list + LLSelectNode *nodep = mSelectedObjects->findNode(objectp); + + // if not in list, add it + if (!nodep) + { + nodep = new LLSelectNode(objectp, true); + mSelectedObjects->addNode(nodep); + llassert_always(nodep->getObject()); + } + else + { + // make this a full-fledged selection + nodep->setTransient(false); + // Move it to the front of the list + mSelectedObjects->moveNodeToFront(nodep); + } + + // Make sure the object is tagged as selected + objectp->setSelected( true ); + + // And make sure we don't consider it as part of a family + nodep->mIndividualSelection = true; + + // Handle face selection + if (objectp->getNumTEs() <= 0) + { + // object has no faces, so don't do anything + } + else if (face == SELECT_ALL_TES) + { + nodep->selectAllTEs(true); + objectp->setAllTESelected(true); + } + else if (0 <= face && face < SELECT_MAX_TES) + { + nodep->selectTE(face, true); + objectp->setTESelected(face, true); + } + else + { + LL_ERRS() << "LLSelectMgr::add face " << face << " out-of-range" << LL_ENDL; + return; + } + + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + updateSelectionCenter(); + dialog_refresh_all(); +} + + +LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32 face) +{ + if (!objectp) + { + mHoverObjects->deleteAllNodes(); + return NULL; + } + + // Can't select yourself + if (objectp->mID == gAgentID) + { + mHoverObjects->deleteAllNodes(); + return NULL; + } + + // Can't select land + if (objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) + { + mHoverObjects->deleteAllNodes(); + return NULL; + } + + mHoverObjects->mPrimaryObject = objectp; + + objectp = objectp->getRootEdit(); + + // is the requested object the same as the existing hover object root? + // NOTE: there is only ever one linked set in mHoverObjects + if (mHoverObjects->getFirstRootObject() != objectp) + { + + // Collect all of the objects + std::vector<LLViewerObject*> objects; + objectp = objectp->getRootEdit(); + objectp->addThisAndNonJointChildren(objects); + + mHoverObjects->deleteAllNodes(); + for (std::vector<LLViewerObject*>::iterator iter = objects.begin(); + iter != objects.end(); ++iter) + { + LLViewerObject* cur_objectp = *iter; + if(!cur_objectp || cur_objectp->isDead()) + { + continue; + } + LLSelectNode* nodep = new LLSelectNode(cur_objectp, false); + nodep->selectTE(face, true); + mHoverObjects->addNodeAtEnd(nodep); + } + + requestObjectPropertiesFamily(objectp); + } + + return mHoverObjects; +} + +LLSelectNode *LLSelectMgr::getHoverNode() +{ + return mHoverObjects->getFirstRootNode(); +} + +LLSelectNode *LLSelectMgr::getPrimaryHoverNode() +{ + return mHoverObjects->mSelectNodeMap[mHoverObjects->mPrimaryObject]; +} + +void LLSelectMgr::highlightObjectOnly(LLViewerObject* objectp) +{ + if (!objectp) + { + return; + } + + if (objectp->getPCode() != LL_PCODE_VOLUME) + { + return; + } + + if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner()) + || (gSavedSettings.getBOOL("SelectMovableOnly") && (!objectp->permMove() || objectp->isPermanentEnforced()))) + { + // only select my own objects + return; + } + + mRectSelectedObjects.insert(objectp); +} + +void LLSelectMgr::highlightObjectAndFamily(LLViewerObject* objectp) +{ + if (!objectp) + { + return; + } + + LLViewerObject* root_obj = (LLViewerObject*)objectp->getRoot(); + + highlightObjectOnly(root_obj); + + LLViewerObject::const_child_list_t& child_list = root_obj->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + highlightObjectOnly(child); + } +} + +// Note that this ignores the "select owned only" flag +// It's also more efficient than calling the single-object version over and over. +void LLSelectMgr::highlightObjectAndFamily(const std::vector<LLViewerObject*>& objects) +{ + for (std::vector<LLViewerObject*>::const_iterator iter1 = objects.begin(); + iter1 != objects.end(); ++iter1) + { + LLViewerObject* object = *iter1; + + if (!object) + { + continue; + } + if (object->getPCode() != LL_PCODE_VOLUME) + { + continue; + } + + LLViewerObject* root = (LLViewerObject*)object->getRoot(); + mRectSelectedObjects.insert(root); + + LLViewerObject::const_child_list_t& child_list = root->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter2 = child_list.begin(); + iter2 != child_list.end(); iter2++) + { + LLViewerObject* child = *iter2; + mRectSelectedObjects.insert(child); + } + } +} + +void LLSelectMgr::unhighlightObjectOnly(LLViewerObject* objectp) +{ + if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) + { + return; + } + + mRectSelectedObjects.erase(objectp); +} + +void LLSelectMgr::unhighlightObjectAndFamily(LLViewerObject* objectp) +{ + if (!objectp) + { + return; + } + + LLViewerObject* root_obj = (LLViewerObject*)objectp->getRoot(); + + unhighlightObjectOnly(root_obj); + + LLViewerObject::const_child_list_t& child_list = root_obj->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + unhighlightObjectOnly(child); + } +} + + +void LLSelectMgr::unhighlightAll() +{ + mRectSelectedObjects.clear(); + mHighlightedObjects->deleteAllNodes(); +} + +LLObjectSelectionHandle LLSelectMgr::selectHighlightedObjects() +{ + if (!mHighlightedObjects->getNumNodes()) + { + return NULL; + } + + //clear primary object + mSelectedObjects->mPrimaryObject = NULL; + + for (LLObjectSelection::iterator iter = getHighlightedObjects()->begin(); + iter != getHighlightedObjects()->end(); ) + { + LLObjectSelection::iterator curiter = iter++; + + LLSelectNode *nodep = *curiter; + LLViewerObject* objectp = nodep->getObject(); + + if (!canSelectObject(objectp)) + { + continue; + } + + // already selected + if (objectp->isSelected()) + { + continue; + } + + LLSelectNode* new_nodep = new LLSelectNode(*nodep); + mSelectedObjects->addNode(new_nodep); + + // flag this object as selected + objectp->setSelected(true); + objectp->setAllTESelected(true); + + mSelectedObjects->mSelectType = getSelectTypeForObject(objectp); + + // request properties on root objects + if (objectp->isRootEdit()) + { + requestObjectPropertiesFamily(objectp); + } + } + + // pack up messages to let sim know these objects are selected + sendSelect(); + unhighlightAll(); + updateSelectionCenter(); + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + updatePointAt(); + + if (mSelectedObjects->getObjectCount()) + { + gEditMenuHandler = this; + } + + return mSelectedObjects; +} + +void LLSelectMgr::deselectHighlightedObjects() +{ + bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); + for (std::set<LLPointer<LLViewerObject> >::iterator iter = mRectSelectedObjects.begin(); + iter != mRectSelectedObjects.end(); iter++) + { + LLViewerObject *objectp = *iter; + if (!select_linked_set) + { + deselectObjectOnly(objectp); + } + else + { + LLViewerObject* root_object = (LLViewerObject*)objectp->getRoot(); + if (root_object->isSelected()) + { + deselectObjectAndFamily(root_object); + } + } + } + + unhighlightAll(); +} + +void LLSelectMgr::addGridObject(LLViewerObject* objectp) +{ + LLSelectNode* nodep = new LLSelectNode(objectp, false); + mGridObjects.addNodeAtEnd(nodep); + + LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + nodep = new LLSelectNode(child, false); + mGridObjects.addNodeAtEnd(nodep); + } +} + +void LLSelectMgr::clearGridObjects() +{ + mGridObjects.deleteAllNodes(); +} + +void LLSelectMgr::setGridMode(EGridMode mode) +{ + mGridMode = mode; + gSavedSettings.setS32("GridMode", mode); + updateSelectionCenter(); +} + +void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale, bool for_snap_guides) +{ + mGridObjects.cleanupNodes(); + + LLViewerObject* first_grid_object = mGridObjects.getFirstObject(); + + if (mGridMode == GRID_MODE_LOCAL && mSelectedObjects->getObjectCount()) + { + //LLViewerObject* root = getSelectedParentObject(mSelectedObjects->getFirstObject()); + mGridOrigin = mSavedSelectionBBox.getCenterAgent(); + mGridScale = mSavedSelectionBBox.getExtentLocal() * 0.5f; + + // DEV-12570 Just taking the saved selection box rotation prevents + // wild rotations of linked sets while in local grid mode + //if(mSelectedObjects->getObjectCount() < 2 || !root || root->mDrawable.isNull()) + { + mGridRotation = mSavedSelectionBBox.getRotation(); + } + /*else //set to the root object + { + mGridRotation = root->getRenderRotation(); + }*/ + } + else if (mGridMode == GRID_MODE_REF_OBJECT && first_grid_object && first_grid_object->mDrawable.notNull()) + { + LLSelectNode *node = mSelectedObjects->findNode(first_grid_object); + if (!for_snap_guides && node) + { + mGridRotation = node->mSavedRotation; + } + else + { + mGridRotation = first_grid_object->getRenderRotation(); + } + + LLVector4a min_extents(F32_MAX); + LLVector4a max_extents(-F32_MAX); + bool grid_changed = false; + for (LLObjectSelection::iterator iter = mGridObjects.begin(); + iter != mGridObjects.end(); ++iter) + { + LLViewerObject* object = (*iter)->getObject(); + LLDrawable* drawable = object->mDrawable; + if (drawable) + { + const LLVector4a* ext = drawable->getSpatialExtents(); + update_min_max(min_extents, max_extents, ext[0]); + update_min_max(min_extents, max_extents, ext[1]); + grid_changed = true; + } + } + if (grid_changed) + { + LLVector4a center, size; + center.setAdd(min_extents, max_extents); + center.mul(0.5f); + size.setSub(max_extents, min_extents); + size.mul(0.5f); + + mGridOrigin.set(center.getF32ptr()); + LLDrawable* drawable = first_grid_object->mDrawable; + if (drawable && drawable->isActive()) + { + mGridOrigin = mGridOrigin * first_grid_object->getRenderMatrix(); + } + mGridScale.set(size.getF32ptr()); + } + } + else // GRID_MODE_WORLD or just plain default + { + const bool non_root_ok = true; + LLViewerObject* first_object = mSelectedObjects->getFirstRootObject(non_root_ok); + + mGridOrigin.clearVec(); + mGridRotation.loadIdentity(); + + mSelectedObjects->mSelectType = getSelectTypeForObject( first_object ); + + switch (mSelectedObjects->mSelectType) + { + case SELECT_TYPE_ATTACHMENT: + if (first_object && first_object->getRootEdit()->mDrawable.notNull()) + { + // this means this object *has* to be an attachment + LLXform* attachment_point_xform = first_object->getRootEdit()->mDrawable->mXform.getParent(); + mGridOrigin = attachment_point_xform->getWorldPosition(); + mGridRotation = attachment_point_xform->getWorldRotation(); + mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution"); + } + break; + case SELECT_TYPE_HUD: + mGridScale = LLVector3(1.f, 1.f, 1.f) * llmin(gSavedSettings.getF32("GridResolution"), 0.5f); + break; + case SELECT_TYPE_WORLD: + mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution"); + break; + } + } + llassert(mGridOrigin.isFinite()); + + origin = mGridOrigin; + rotation = mGridRotation; + scale = mGridScale; +} + +//----------------------------------------------------------------------------- +// remove() - an array of objects +//----------------------------------------------------------------------------- + +void LLSelectMgr::remove(std::vector<LLViewerObject*>& objects) +{ + for (std::vector<LLViewerObject*>::iterator iter = objects.begin(); + iter != objects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + LLSelectNode* nodep = mSelectedObjects->findNode(objectp); + if (nodep) + { + objectp->setSelected(false); + mSelectedObjects->removeNode(nodep); + nodep = NULL; + } + } + updateSelectionCenter(); + dialog_refresh_all(); +} + + +//----------------------------------------------------------------------------- +// remove() - a single object +//----------------------------------------------------------------------------- +void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, bool undoable) +{ + // get object node (and verify it is in the selected list) + LLSelectNode *nodep = mSelectedObjects->findNode(objectp); + if (!nodep) + { + return; + } + + // if face = all, remove object from list + if ((objectp->getNumTEs() <= 0) || (te == SELECT_ALL_TES)) + { + // Remove all faces (or the object doesn't have faces) so remove the node + mSelectedObjects->removeNode(nodep); + nodep = NULL; + objectp->setSelected( false ); + } + else if (0 <= te && te < SELECT_MAX_TES) + { + // ...valid face, check to see if it was on + if (nodep->isTESelected(te)) + { + nodep->selectTE(te, false); + objectp->setTESelected(te, false); + } + else + { + LL_ERRS() << "LLSelectMgr::remove - tried to remove TE " << te << " that wasn't selected" << LL_ENDL; + return; + } + + // ...check to see if this operation turned off all faces + bool found = false; + for (S32 i = 0; i < nodep->getObject()->getNumTEs(); i++) + { + found = found || nodep->isTESelected(i); + } + + // ...all faces now turned off, so remove + if (!found) + { + mSelectedObjects->removeNode(nodep); + nodep = NULL; + objectp->setSelected( false ); + // *FIXME: Doesn't update simulator that object is no longer selected + } + } + else + { + // ...out of range face + LL_ERRS() << "LLSelectMgr::remove - TE " << te << " out of range" << LL_ENDL; + } + + updateSelectionCenter(); + dialog_refresh_all(); +} + + +//----------------------------------------------------------------------------- +// removeAll() +//----------------------------------------------------------------------------- +void LLSelectMgr::removeAll() +{ + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++ ) + { + LLViewerObject *objectp = (*iter)->getObject(); + objectp->setSelected( false ); + } + + mSelectedObjects->deleteAllNodes(); + + updateSelectionCenter(); + dialog_refresh_all(); +} + +//----------------------------------------------------------------------------- +// promoteSelectionToRoot() +//----------------------------------------------------------------------------- +void LLSelectMgr::promoteSelectionToRoot() +{ + std::set<LLViewerObject*> selection_set; + + bool selection_changed = false; + + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); ) + { + LLObjectSelection::iterator curiter = iter++; + LLSelectNode* nodep = *curiter; + LLViewerObject* object = nodep->getObject(); + + if (nodep->mIndividualSelection) + { + selection_changed = true; + } + + LLViewerObject* parentp = object; + while(parentp->getParent() && !(parentp->isRootEdit())) + { + parentp = (LLViewerObject*)parentp->getParent(); + } + + selection_set.insert(parentp); + } + + if (selection_changed) + { + deselectAll(); + + std::set<LLViewerObject*>::iterator set_iter; + for (set_iter = selection_set.begin(); set_iter != selection_set.end(); ++set_iter) + { + selectObjectAndFamily(*set_iter); + } + } +} + +//----------------------------------------------------------------------------- +// demoteSelectionToIndividuals() +//----------------------------------------------------------------------------- +void LLSelectMgr::demoteSelectionToIndividuals() +{ + std::vector<LLViewerObject*> objects; + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + LLViewerObject* object = (*iter)->getObject(); + object->addThisAndNonJointChildren(objects); + } + + if (!objects.empty()) + { + deselectAll(); + for (std::vector<LLViewerObject*>::iterator iter = objects.begin(); + iter != objects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + selectObjectOnly(objectp); + } + } +} + +//----------------------------------------------------------------------------- +// dump() +//----------------------------------------------------------------------------- +void LLSelectMgr::dump() +{ + LL_INFOS() << "Selection Manager: " << mSelectedObjects->getNumNodes() << " items" << LL_ENDL; + + LL_INFOS() << "TE mode " << mTEMode << LL_ENDL; + + S32 count = 0; + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLViewerObject* objectp = (*iter)->getObject(); + LL_INFOS() << "Object " << count << " type " << LLPrimitive::pCodeToString(objectp->getPCode()) << LL_ENDL; + LL_INFOS() << " hasLSL " << objectp->flagScripted() << LL_ENDL; + LL_INFOS() << " hasTouch " << objectp->flagHandleTouch() << LL_ENDL; + LL_INFOS() << " hasMoney " << objectp->flagTakesMoney() << LL_ENDL; + LL_INFOS() << " getposition " << objectp->getPosition() << LL_ENDL; + LL_INFOS() << " getpositionAgent " << objectp->getPositionAgent() << LL_ENDL; + LL_INFOS() << " getpositionRegion " << objectp->getPositionRegion() << LL_ENDL; + LL_INFOS() << " getpositionGlobal " << objectp->getPositionGlobal() << LL_ENDL; + LLDrawable* drawablep = objectp->mDrawable; + LL_INFOS() << " " << (drawablep&& drawablep->isVisible() ? "visible" : "invisible") << LL_ENDL; + LL_INFOS() << " " << (drawablep&& drawablep->isState(LLDrawable::FORCE_INVISIBLE) ? "force_invisible" : "") << LL_ENDL; + count++; + } + + // Face iterator + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + for (S32 te = 0; te < objectp->getNumTEs(); ++te ) + { + if (node->isTESelected(te)) + { + LL_INFOS() << "Object " << objectp << " te " << te << LL_ENDL; + } + } + } + + LL_INFOS() << mHighlightedObjects->getNumNodes() << " objects currently highlighted." << LL_ENDL; + + LL_INFOS() << "Center global " << mSelectionCenterGlobal << LL_ENDL; +} + +//----------------------------------------------------------------------------- +// cleanup() +//----------------------------------------------------------------------------- +void LLSelectMgr::cleanup() +{ + mSilhouetteImagep = NULL; +} + + +//--------------------------------------------------------------------------- +// Manipulate properties of selected objects +//--------------------------------------------------------------------------- + +struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor +{ + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + return true; + } +}; + +void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item) +{ + if (!item) + { + return; + } + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID()); + + for (iterator iter = begin(); iter != end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = (*iter)->getObject(); + if (!object) + { + continue; + } + + S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); + bool texture_copied = false; + bool updated = false; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + //(no-copy) textures must be moved to the object's inventory only once + // without making any copies + if (!texture_copied) + { + LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + texture_copied = true; + } + + // apply texture for the selected faces + add(LLStatViewer::EDIT_TEXTURE, 1); + object->setTEImage(te, image); + updated = true; + } + } + + if (updated) // not nessesary? sendTEUpdate update supposed to be done by sendfunc + { + dialog_refresh_all(); + + // send the update to the simulator + object->sendTEUpdate(); + } + } +} + +bool LLObjectSelection::applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item) +{ + if (!item) + { + return false; + } + + LLUUID asset_id = item->getAssetUUID(); + if (asset_id.isNull()) + { + asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + } + + bool material_copied_all_faces = true; + + for (iterator iter = begin(); iter != end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = (*iter)->getObject(); + if (!object) + { + continue; + } + + S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); + bool material_copied = false; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + //(no-copy), (no-modify), and (no-transfer) materials must be moved to the object's inventory only once + // without making any copies + if (!material_copied && asset_id.notNull()) + { + material_copied = (bool)LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + if (!material_copied) + { + // Applying the material is not possible for this object given the current inventory + material_copied_all_faces = false; + break; + } + + // apply texture for the selected faces + // blank out most override data on the server + //add(LLStatViewer::EDIT_TEXTURE, 1); + object->setRenderMaterialID(te, asset_id); + } + } + } + + LLGLTFMaterialList::flushUpdates(); + + return material_copied_all_faces; +} + + +//----------------------------------------------------------------------------- +// selectionSetImage() +//----------------------------------------------------------------------------- +// *TODO: re-arch texture applying out of lltooldraganddrop +bool LLSelectMgr::selectionSetImage(const LLUUID& imageid) +{ + // First for (no copy) textures and multiple object selection + LLViewerInventoryItem* item = gInventory.getItem(imageid); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_DEBUGS() << "Attempted to apply no-copy texture " << imageid + << " to multiple objects" << LL_ENDL; + + LLNotificationsUtil::add("FailedToApplyTextureNoCopyToMultiple"); + return false; + } + + struct f : public LLSelectedTEFunctor + { + LLViewerInventoryItem* mItem; + LLUUID mImageID; + f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} + bool apply(LLViewerObject* objectp, S32 te) + { + if(!objectp || !objectp->permModify()) + { + return false; + } + + // Might be better to run willObjectAcceptInventory + if (mItem && objectp->isAttachment()) + { + const LLPermissions& perm = mItem->getPermissions(); + bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + if (!unrestricted) + { + // Attachments are in world and in inventory simultaneously, + // at the moment server doesn't support such a situation. + return false; + } + } + + if (mItem) + { + LLToolDragAndDrop::dropTextureOneFace(objectp, + te, + mItem, + LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null, + false); + } + else // not an inventory item + { + // Texture picker defaults aren't inventory items + // * Don't need to worry about permissions for them + // * Can just apply the texture and be done with it. + objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + } + + return true; + } + }; + + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + getSelection()->applyNoCopyTextureToTEs(item); + } + else + { + f setfunc(item, imageid); + getSelection()->applyToTEs(&setfunc); + } + + + struct g : public LLSelectedObjectFunctor + { + LLViewerInventoryItem* mItem; + g(LLViewerInventoryItem* item) : mItem(item) {} + virtual bool apply(LLViewerObject* object) + { + if (!mItem) + { + object->sendTEUpdate(); + // 1 particle effect per object + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, true); + effectp->setSourceObject(gAgentAvatarp); + effectp->setTargetObject(object); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + } + return true; + } + } sendfunc(item); + getSelection()->applyToObjects(&sendfunc); + + return true; +} + +//----------------------------------------------------------------------------- +// selectionSetGLTFMaterial() +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) +{ + // First for (no copy) textures and multiple object selection + LLViewerInventoryItem* item = gInventory.getItem(mat_id); + if (item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1)) + { + LL_DEBUGS() << "Attempted to apply no-copy material " << mat_id + << "to multiple objects" << LL_ENDL; + + LLNotificationsUtil::add("FailedToApplyGLTFNoCopyToMultiple"); + return false; + } + + struct f : public LLSelectedTEFunctor + { + LLViewerInventoryItem* mItem; + LLUUID mMatId; + bool material_copied_any_face = false; + bool material_copied_all_faces = true; + f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mMatId(id) {} + bool apply(LLViewerObject* objectp, S32 te) + { + if (!objectp || !objectp->permModify()) + { + return false; + } + LLUUID asset_id = mMatId; + if (mItem) + { + const LLPermissions& perm = mItem->getPermissions(); + bool from_library = perm.getOwner() == ALEXANDRIA_LINDEN_ID; + if (objectp->isAttachment()) + { + bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + + if (!unrestricted && !from_library) + { + // Attachments are in world and in inventory simultaneously, + // at the moment server doesn't support such a situation. + return false; + } + } + + if (!from_library + // Check if item may be copied into the object's inventory + && !LLToolDragAndDrop::handleDropMaterialProtections(objectp, mItem, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null)) + { + return false; + } + + asset_id = mItem->getAssetUUID(); + if (asset_id.isNull()) + { + asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID; + } + } + + // Blank out most override data on the object and send to server + objectp->setRenderMaterialID(te, asset_id); + + return true; + } + }; + + bool success = true; + if (item + && (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) || + !item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) || + !item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()) + ) + && item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID + ) + { + success = success && getSelection()->applyRestrictedPbrMaterialToTEs(item); + } + else + { + f setfunc(item, mat_id); + success = success && getSelection()->applyToTEs(&setfunc); + } + + struct g : public LLSelectedObjectFunctor + { + LLViewerInventoryItem* mItem; + g(LLViewerInventoryItem* item) : mItem(item) {} + virtual bool apply(LLViewerObject* object) + { + if (object && !object->permModify()) + { + return false; + } + + if (!mItem) + { + // 1 particle effect per object + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, true); + effectp->setSourceObject(gAgentAvatarp); + effectp->setTargetObject(object); + effectp->setDuration(LL_HUD_DUR_SHORT); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + } + + dialog_refresh_all(); + object->sendTEUpdate(); + return true; + } + } sendfunc(item); + success = success && getSelection()->applyToObjects(&sendfunc); + + LLGLTFMaterialList::flushUpdates(); + + return success; +} + +//----------------------------------------------------------------------------- +// selectionSetColor() +//----------------------------------------------------------------------------- +void LLSelectMgr::selectionSetColor(const LLColor4 &color) +{ + struct f : public LLSelectedTEFunctor + { + LLColor4 mColor; + f(const LLColor4& c) : mColor(c) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + object->setTEColor(te, mColor); + } + return true; + } + } setfunc(color); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +//----------------------------------------------------------------------------- +// selectionSetColorOnly() +//----------------------------------------------------------------------------- +void LLSelectMgr::selectionSetColorOnly(const LLColor4 &color) +{ + struct f : public LLSelectedTEFunctor + { + LLColor4 mColor; + f(const LLColor4& c) : mColor(c) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLColor4 prev_color = object->getTE(te)->getColor(); + mColor.mV[VALPHA] = prev_color.mV[VALPHA]; + // update viewer side color in anticipation of update from simulator + object->setTEColor(te, mColor); + } + return true; + } + } setfunc(color); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +//----------------------------------------------------------------------------- +// selectionSetAlphaOnly() +//----------------------------------------------------------------------------- +void LLSelectMgr::selectionSetAlphaOnly(const F32 alpha) +{ + struct f : public LLSelectedTEFunctor + { + F32 mAlpha; + f(const F32& a) : mAlpha(a) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLColor4 prev_color = object->getTE(te)->getColor(); + prev_color.mV[VALPHA] = mAlpha; + // update viewer side color in anticipation of update from simulator + object->setTEColor(te, prev_color); + } + return true; + } + } setfunc(alpha); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionRevertColors() +{ + struct f : public LLSelectedTEFunctor + { + LLObjectSelectionHandle mSelectedObjects; + f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLSelectNode* nodep = mSelectedObjects->findNode(object); + if (nodep && te < (S32)nodep->mSavedColors.size()) + { + LLColor4 color = nodep->mSavedColors[te]; + // update viewer side color in anticipation of update from simulator + object->setTEColor(te, color); + } + } + return true; + } + } setfunc(mSelectedObjects); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionRevertShinyColors() +{ + struct f : public LLSelectedTEFunctor + { + LLObjectSelectionHandle mSelectedObjects; + f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLSelectNode* nodep = mSelectedObjects->findNode(object); + if (nodep && te < (S32)nodep->mSavedShinyColors.size()) + { + LLColor4 color = nodep->mSavedShinyColors[te]; + // update viewer side color in anticipation of update from simulator + LLMaterialPtr old_mat = object->getTE(te)->getMaterialParams(); + if (!old_mat.isNull()) + { + LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat); + new_mat->setSpecularLightColor(color); + object->getTE(te)->setMaterialParams(new_mat); + LLMaterialMgr::getInstance()->put(object->getID(), te, *new_mat); + } + } + } + return true; + } + } setfunc(mSelectedObjects); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +bool LLSelectMgr::selectionRevertTextures() +{ + struct f : public LLSelectedTEFunctor + { + LLObjectSelectionHandle mSelectedObjects; + f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + LLSelectNode* nodep = mSelectedObjects->findNode(object); + if (nodep && te < (S32)nodep->mSavedTextures.size()) + { + LLUUID id = nodep->mSavedTextures[te]; + // update textures on viewer side + if (id.isNull()) + { + // this was probably a no-copy texture, leave image as-is + return false; + } + else + { + object->setTEImage(te, LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + + } + } + } + return true; + } + } setfunc(mSelectedObjects); + bool revert_successful = getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); + + return revert_successful; +} + +void LLSelectMgr::selectionRevertGLTFMaterials() +{ + struct f : public LLSelectedTEFunctor + { + LLObjectSelectionHandle mSelectedObjects; + f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} + bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && !objectp->permModify()) + { + return false; + } + + LLSelectNode* nodep = mSelectedObjects->findNode(objectp); + if (nodep && te < (S32)nodep->mSavedGLTFMaterialIds.size()) + { + // Restore base material + LLUUID asset_id = nodep->mSavedGLTFMaterialIds[te]; + + // Update material locally + objectp->setRenderMaterialID(te, asset_id, false /*wait for LLGLTFMaterialList update*/); + objectp->setTEGLTFMaterialOverride(te, nodep->mSavedGLTFOverrideMaterials[te]); + + // Enqueue update to server + if (asset_id.notNull()) + { + // Restore overrides and base material + LLGLTFMaterialList::queueApply(objectp, te, asset_id, nodep->mSavedGLTFOverrideMaterials[te]); + } + else + { + //blank override out + LLGLTFMaterialList::queueApply(objectp, te, asset_id); + } + + } + return true; + } + } setfunc(mSelectedObjects); + getSelection()->applyToTEs(&setfunc); +} + +void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) +{ + struct f : public LLSelectedTEFunctor + { + U8 mBump; + f(const U8& b) : mBump(b) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + // update viewer side color in anticipation of update from simulator + object->setTEBumpmap(te, mBump); + } + return true; + } + } setfunc(bumpmap); + + LLViewerInventoryItem* item = gInventory.getItem(image_id); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL; + return; + } + + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) + { + return; + } + const LLPermissions& perm = item->getPermissions(); + bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + bool attached = object->isAttachment(); + if (attached && !unrestricted) + { + // Attachments are in world and in inventory simultaneously, + // at the moment server doesn't support such a situation. + return; + } + LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetTexGen(U8 texgen) +{ + struct f : public LLSelectedTEFunctor + { + U8 mTexgen; + f(const U8& t) : mTexgen(t) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + // update viewer side color in anticipation of update from simulator + object->setTETexGen(te, mTexgen); + } + return true; + } + } setfunc(texgen); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + + +void LLSelectMgr::selectionSetShiny(U8 shiny, const LLUUID &image_id) +{ + struct f : public LLSelectedTEFunctor + { + U8 mShiny; + f(const U8& t) : mShiny(t) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + // update viewer side color in anticipation of update from simulator + object->setTEShiny(te, mShiny); + } + return true; + } + } setfunc(shiny); + + LLViewerInventoryItem* item = gInventory.getItem(image_id); + if(item + && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) + && (mSelectedObjects->getNumNodes() > 1) ) + { + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" << LL_ENDL; + return; + } + + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) + { + return; + } + const LLPermissions& perm = item->getPermissions(); + bool unrestricted = (perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED; + bool attached = object->isAttachment(); + if (attached && !unrestricted) + { + // Attachments are in world and in inventory simultaneously, + // at the moment server doesn't support such a situation. + return; + } + LLToolDragAndDrop::handleDropMaterialProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + } + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetFullbright(U8 fullbright) +{ + struct f : public LLSelectedTEFunctor + { + U8 mFullbright; + f(const U8& t) : mFullbright(t) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + // update viewer side color in anticipation of update from simulator + object->setTEFullbright(te, mFullbright); + } + return true; + } + } setfunc(fullbright); + getSelection()->applyToTEs(&setfunc); + + struct g : public LLSelectedObjectFunctor + { + U8 mFullbright; + g(const U8& t) : mFullbright(t) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + if (mFullbright) + { + U8 material = object->getMaterial(); + U8 mcode = material & LL_MCODE_MASK; + if (mcode == LL_MCODE_LIGHT) + { + mcode = LL_MCODE_GLASS; + material = (material & ~LL_MCODE_MASK) | mcode; + object->setMaterial(material); + object->sendMaterialUpdate(); + } + } + } + return true; + } + } sendfunc(fullbright); + getSelection()->applyToObjects(&sendfunc); +} + +// This function expects media_data to be a map containing relevant +// media data name/value pairs (e.g. home_url, etc.) +void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) +{ + struct f : public LLSelectedTEFunctor + { + U8 mMediaFlags; + const LLSD &mMediaData; + f(const U8& t, const LLSD& d) : mMediaFlags(t), mMediaData(d) {} + bool apply(LLViewerObject* object, S32 te) + { + if (object->permModify()) + { + // If we are adding media, then check the current state of the + // media data on this face. + // - If it does not have media, AND we are NOT setting the HOME URL, then do NOT add media to this + // face. + // - If it does not have media, and we ARE setting the HOME URL, add media to this face. + // - If it does already have media, add/update media to/on this face + // If we are removing media, just do it (ignore the passed-in LLSD). + if (mMediaFlags & LLTextureEntry::MF_HAS_MEDIA) + { + llassert(mMediaData.isMap()); + const LLTextureEntry *texture_entry = object->getTE(te); + if (!mMediaData.isMap() || + ((NULL != texture_entry) && !texture_entry->hasMedia() && !mMediaData.has(LLMediaEntry::HOME_URL_KEY))) + { + // skip adding/updating media + } + else { + // Add/update media + object->setTEMediaFlags(te, mMediaFlags); + LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object); + llassert(NULL != vo); + if (NULL != vo) + { + vo->syncMediaData(te, mMediaData, true/*merge*/, true/*ignore_agent*/); + } + } + } + else + { + // delete media (or just set the flags) + object->setTEMediaFlags(te, mMediaFlags); + } + } + return true; + } + } setfunc(media_type, media_data); + getSelection()->applyToTEs(&setfunc); + + struct f2 : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + LLVOVolume *vo = dynamic_cast<LLVOVolume*>(object); + llassert(NULL != vo); + // It's okay to skip this object if hasMedia() is false... + // the sendTEUpdate() above would remove all media data if it were + // there. + if (NULL != vo && vo->hasMedia()) + { + // Send updated media data FOR THE ENTIRE OBJECT + vo->sendMediaDataUpdate(); + } + } + return true; + } + } func2; + mSelectedObjects->applyToObjects( &func2 ); +} + +void LLSelectMgr::selectionSetGlow(F32 glow) +{ + struct f1 : public LLSelectedTEFunctor + { + F32 mGlow; + f1(F32 glow) : mGlow(glow) {}; + bool apply(LLViewerObject* object, S32 face) + { + if (object->permModify()) + { + // update viewer side color in anticipation of update from simulator + object->setTEGlow(face, mGlow); + } + return true; + } + } func1(glow); + mSelectedObjects->applyToTEs( &func1 ); + + struct f2 : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + return true; + } + } func2; + mSelectedObjects->applyToObjects( &func2 ); +} + +void LLSelectMgr::selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func, int te) +{ + struct f1 : public LLSelectedTEFunctor + { + LLMaterialPtr mMaterial; + f1(LLSelectedTEMaterialFunctor* material_func, int te) : _material_func(material_func), _specific_te(te) {} + + bool apply(LLViewerObject* object, S32 te) + { + if (_specific_te == -1 || (te == _specific_te)) + { + if (object && object->permModify() && _material_func) + { + LLTextureEntry* tep = object->getTE(te); + if (tep) + { + LLMaterialPtr current_material = tep->getMaterialParams(); + _material_func->apply(object, te, tep, current_material); + } + } + } + return true; + } + + LLSelectedTEMaterialFunctor* _material_func; + int _specific_te; + } func1(material_func, te); + mSelectedObjects->applyToTEs( &func1 ); + + struct f2 : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + return true; + } + } func2; + mSelectedObjects->applyToObjects( &func2 ); +} + +void LLSelectMgr::selectionRemoveMaterial() +{ + struct f1 : public LLSelectedTEFunctor + { + bool apply(LLViewerObject* object, S32 face) + { + if (object->permModify()) + { + LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL; + LLMaterialMgr::getInstance()->remove(object->getID(),face); + object->setTEMaterialParams(face, NULL); + } + return true; + } + } func1; + mSelectedObjects->applyToTEs( &func1 ); + + struct f2 : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + return true; + } + } func2; + mSelectedObjects->applyToObjects( &func2 ); +} + + +//----------------------------------------------------------------------------- +// findObjectPermissions() +//----------------------------------------------------------------------------- +LLPermissions* LLSelectMgr::findObjectPermissions(const LLViewerObject* object) +{ + for (LLObjectSelection::valid_iterator iter = getSelection()->valid_begin(); + iter != getSelection()->valid_end(); iter++ ) + { + LLSelectNode* nodep = *iter; + if (nodep->getObject() == object) + { + return nodep->mPermissions; + } + } + + return NULL; +} + + +//----------------------------------------------------------------------------- +// selectionGetGlow() +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectionGetGlow(F32 *glow) +{ + bool identical; + F32 lglow = 0.f; + struct f1 : public LLSelectedTEGetFunctor<F32> + { + F32 get(LLViewerObject* object, S32 face) + { + return object->getTE(face)->getGlow(); + } + } func; + identical = mSelectedObjects->getSelectedTEValue( &func, lglow ); + + *glow = lglow; + return identical; +} + + +void LLSelectMgr::selectionSetPhysicsType(U8 type) +{ + struct f : public LLSelectedObjectFunctor + { + U8 mType; + f(const U8& t) : mType(t) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsShapeType(mType); + object->updateFlags(true); + } + return true; + } + } sendfunc(type); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetFriction(F32 friction) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mFriction; + f(const F32& friction) : mFriction(friction) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsFriction(mFriction); + object->updateFlags(true); + } + return true; + } + } sendfunc(friction); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetGravity(F32 gravity ) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mGravity; + f(const F32& gravity) : mGravity(gravity) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsGravity(mGravity); + object->updateFlags(true); + } + return true; + } + } sendfunc(gravity); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetDensity(F32 density ) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mDensity; + f(const F32& density ) : mDensity(density) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsDensity(mDensity); + object->updateFlags(true); + } + return true; + } + } sendfunc(density); + getSelection()->applyToObjects(&sendfunc); +} + +void LLSelectMgr::selectionSetRestitution(F32 restitution) +{ + struct f : public LLSelectedObjectFunctor + { + F32 mRestitution; + f(const F32& restitution ) : mRestitution(restitution) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + object->setPhysicsRestitution(mRestitution); + object->updateFlags(true); + } + return true; + } + } sendfunc(restitution); + getSelection()->applyToObjects(&sendfunc); +} + + +//----------------------------------------------------------------------------- +// selectionSetMaterial() +//----------------------------------------------------------------------------- +void LLSelectMgr::selectionSetMaterial(U8 material) +{ + struct f : public LLSelectedObjectFunctor + { + U8 mMaterial; + f(const U8& t) : mMaterial(t) {} + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + U8 cur_material = object->getMaterial(); + U8 material = mMaterial | (cur_material & ~LL_MCODE_MASK); + object->setMaterial(material); + object->sendMaterialUpdate(); + } + return true; + } + } sendfunc(material); + getSelection()->applyToObjects(&sendfunc); +} + +// true if all selected objects have this PCode +bool LLSelectMgr::selectionAllPCode(LLPCode code) +{ + struct f : public LLSelectedObjectFunctor + { + LLPCode mCode; + f(const LLPCode& t) : mCode(t) {} + virtual bool apply(LLViewerObject* object) + { + if (object->getPCode() != mCode) + { + return false; + } + return true; + } + } func(code); + bool res = getSelection()->applyToObjects(&func); + return res; +} + +bool LLSelectMgr::selectionGetIncludeInSearch(bool* include_in_search_out) +{ + LLViewerObject *object = mSelectedObjects->getFirstRootObject(); + if (!object) return false; + + bool include_in_search = object->getIncludeInSearch(); + + bool identical = true; + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + LLViewerObject* object = (*iter)->getObject(); + + if ( include_in_search != object->getIncludeInSearch()) + { + identical = false; + break; + } + } + + *include_in_search_out = include_in_search; + return identical; +} + +void LLSelectMgr::selectionSetIncludeInSearch(bool include_in_search) +{ + LLViewerObject* object = NULL; + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + object = (*iter)->getObject(); + object->setIncludeInSearch(include_in_search); + } + sendListToRegions( + "ObjectIncludeInSearch", + packAgentAndSessionID, + packObjectIncludeInSearch, + logNoOp, + &include_in_search, + SEND_ONLY_ROOTS); +} + +bool LLSelectMgr::selectionGetClickAction(U8 *out_action) +{ + LLViewerObject *object = mSelectedObjects->getFirstObject(); + if (!object) + { + return false; + } + + U8 action = object->getClickAction(); + *out_action = action; + + struct f : public LLSelectedObjectFunctor + { + U8 mAction; + f(const U8& t) : mAction(t) {} + virtual bool apply(LLViewerObject* object) + { + if ( mAction != object->getClickAction()) + { + return false; + } + return true; + } + } func(action); + bool res = getSelection()->applyToObjects(&func); + return res; +} + +void LLSelectMgr::selectionSetClickAction(U8 action) +{ + struct f : public LLSelectedObjectFunctor + { + U8 mAction; + f(const U8& t) : mAction(t) {} + virtual bool apply(LLViewerObject* object) + { + object->setClickAction(mAction); + return true; + } + } func(action); + getSelection()->applyToObjects(&func); + + sendListToRegions("ObjectClickAction", + packAgentAndSessionID, + packObjectClickAction, + logNoOp, + &action, + SEND_INDIVIDUALS); +} + + +//----------------------------------------------------------------------------- +// godlike requests +//----------------------------------------------------------------------------- + +typedef std::pair<const std::string, const std::string> godlike_request_t; + +void LLSelectMgr::sendGodlikeRequest(const std::string& request, const std::string& param) +{ + // If the agent is neither godlike nor an estate owner, the server + // will reject the request. + std::string message_type; + if (gAgent.isGodlike()) + { + message_type = "GodlikeMessage"; + } + else + { + message_type = "EstateOwnerMessage"; + } + + godlike_request_t data(request, param); + if(!mSelectedObjects->getRootObjectCount()) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessage(message_type.c_str()); + LLSelectMgr::packGodlikeHead(&data); + gAgent.sendReliableMessage(); + } + else + { + sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, logNoOp, &data, SEND_ONLY_ROOTS); + } +} + +void LLSelectMgr::packGodlikeHead(void* user_data) +{ + LLMessageSystem* msg = gMessageSystem; + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID("TransactionID", LLUUID::null); + godlike_request_t* data = (godlike_request_t*)user_data; + msg->nextBlock("MethodData"); + msg->addString("Method", data->first); + msg->addUUID("Invoice", LLUUID::null); + + // The parameters used to be restricted to either string or + // integer. This mimics that behavior under the new 'string-only' + // parameter list by not packing a string if there wasn't one + // specified. The object ids will be packed in the + // packObjectIDAsParam() method. + if(data->second.size() > 0) + { + msg->nextBlock("ParamList"); + msg->addString("Parameter", data->second); + } +} + +// static +void LLSelectMgr::logNoOp(LLSelectNode* node, void *) +{ +} + +// static +void LLSelectMgr::logAttachmentRequest(LLSelectNode* node, void *) +{ + LLAttachmentsMgr::instance().onAttachmentRequested(node->mItemID); +} + +// static +void LLSelectMgr::logDetachRequest(LLSelectNode* node, void *) +{ + LLAttachmentsMgr::instance().onDetachRequested(node->mItemID); +} + +// static +void LLSelectMgr::packObjectIDAsParam(LLSelectNode* node, void *) +{ + std::string buf = llformat("%u", node->getObject()->getLocalID()); + gMessageSystem->nextBlock("ParamList"); + gMessageSystem->addString("Parameter", buf); +} + +//----------------------------------------------------------------------------- +// selectionTexScaleAutofit() +//----------------------------------------------------------------------------- +void LLSelectMgr::selectionTexScaleAutofit(F32 repeats_per_meter) +{ + struct f : public LLSelectedTEFunctor + { + F32 mRepeatsPerMeter; + f(const F32& t) : mRepeatsPerMeter(t) {} + bool apply(LLViewerObject* object, S32 te) + { + + if (object->permModify()) + { + // Compute S,T to axis mapping + U32 s_axis, t_axis; + if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis)) + { + return true; + } + + F32 new_s = object->getScale().mV[s_axis] * mRepeatsPerMeter; + F32 new_t = object->getScale().mV[t_axis] * mRepeatsPerMeter; + + object->setTEScale(te, new_s, new_t); + } + return true; + } + } setfunc(repeats_per_meter); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + + + +// Called at the end of a scale operation, this adjusts the textures to attempt to +// maintain a constant repeats per meter. +// BUG: Only works for flex boxes. +//----------------------------------------------------------------------------- +// adjustTexturesByScale() +//----------------------------------------------------------------------------- +void LLSelectMgr::adjustTexturesByScale(bool send_to_sim, bool stretch) +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++) + { + LLSelectNode* selectNode = *iter; + LLViewerObject* object = selectNode->getObject(); + + if (!object) + { + continue; + } + + if (!object->permModify()) + { + continue; + } + + if (object->getNumTEs() == 0) + { + continue; + } + + bool send = false; + + for (U8 te_num = 0; te_num < object->getNumTEs(); te_num++) + { + const LLTextureEntry* tep = object->getTE(te_num); + + bool planar = tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR; + if (planar == stretch) + { + // Figure out how S,T changed with scale operation + U32 s_axis, t_axis; + if (!LLPrimitive::getTESTAxes(te_num, &s_axis, &t_axis)) + { + continue; + } + + LLVector3 object_scale = object->getScale(); + LLVector3 diffuse_scale_ratio = selectNode->mTextureScaleRatios[te_num]; + + // We like these to track together. NORSPEC-96 + // + LLVector3 normal_scale_ratio = diffuse_scale_ratio; + LLVector3 specular_scale_ratio = diffuse_scale_ratio; + + // Apply new scale to face + if (planar) + { + F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]/object_scale.mV[s_axis]; + F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]/object_scale.mV[t_axis]; + + F32 normal_scale_s = normal_scale_ratio.mV[s_axis]/object_scale.mV[s_axis]; + F32 normal_scale_t = normal_scale_ratio.mV[t_axis]/object_scale.mV[t_axis]; + + F32 specular_scale_s = specular_scale_ratio.mV[s_axis]/object_scale.mV[s_axis]; + F32 specular_scale_t = specular_scale_ratio.mV[t_axis]/object_scale.mV[t_axis]; + + object->setTEScale(te_num, diffuse_scale_s, diffuse_scale_t); + + LLTextureEntry* tep = object->getTE(te_num); + + if (tep && !tep->getMaterialParams().isNull()) + { + LLMaterialPtr orig = tep->getMaterialParams(); + LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + p->setNormalRepeat(normal_scale_s, normal_scale_t); + p->setSpecularRepeat(specular_scale_s, specular_scale_t); + + LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p); + } + } + else + { + + F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]*object_scale.mV[s_axis]; + F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]*object_scale.mV[t_axis]; + + F32 normal_scale_s = normal_scale_ratio.mV[s_axis]*object_scale.mV[s_axis]; + F32 normal_scale_t = normal_scale_ratio.mV[t_axis]*object_scale.mV[t_axis]; + + F32 specular_scale_s = specular_scale_ratio.mV[s_axis]*object_scale.mV[s_axis]; + F32 specular_scale_t = specular_scale_ratio.mV[t_axis]*object_scale.mV[t_axis]; + + object->setTEScale(te_num, diffuse_scale_s,diffuse_scale_t); + + LLTextureEntry* tep = object->getTE(te_num); + + if (tep && !tep->getMaterialParams().isNull()) + { + LLMaterialPtr orig = tep->getMaterialParams(); + LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + + p->setNormalRepeat(normal_scale_s, normal_scale_t); + p->setSpecularRepeat(specular_scale_s, specular_scale_t); + + LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p); + } + } + send = send_to_sim; + } + } + + if (send) + { + object->sendTEUpdate(); + } + } +} + +//----------------------------------------------------------------------------- +// selectGetAllRootsValid() +// Returns true if the viewer has information on all selected objects +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetAllRootsValid() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); ++iter ) + { + LLSelectNode* node = *iter; + if( !node->mValid ) + { + return false; + } + } + return true; +} + + +//----------------------------------------------------------------------------- +// selectGetAllValid() +// Returns true if the viewer has information on all selected objects +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetAllValid() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); ++iter ) + { + LLSelectNode* node = *iter; + if( !node->mValid ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetAllValidAndObjectsFound() - return true if selections are +// valid and objects are found. +// +// For EXT-3114 - same as selectGetModify() without the modify check. +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetAllValidAndObjectsFound() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetModify() - return true if current agent can modify all +// selected objects. +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetModify() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( !object->permModify() ) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsModify() - return true if current agent can modify all +// selected root objects. +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsModify() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( !object->permModify() ) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetSameRegion() - return true if all objects are in same region +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetSameRegion() +{ + if (getSelection()->isEmpty()) + { + return true; + } + LLViewerObject* object = getSelection()->getFirstObject(); + if (!object) + { + return false; + } + LLViewerRegion* current_region = object->getRegion(); + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + object = node->getObject(); + if (!node->mValid || !object || current_region != object->getRegion()) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetNonPermanentEnforced() - return true if all objects are not +// permanent enforced +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetNonPermanentEnforced() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( object->isPermanentEnforced()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsNonPermanentEnforced() - return true if all root objects are +// not permanent enforced +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsNonPermanentEnforced() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( object->isPermanentEnforced()) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetPermanent() - return true if all objects are permanent +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetPermanent() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( !object->flagObjectPermanent()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsPermanent() - return true if all root objects are +// permanent +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsPermanent() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( !object->flagObjectPermanent()) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetCharacter() - return true if all objects are character +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetCharacter() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( !object->flagCharacter()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsCharacter() - return true if all root objects are +// character +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsCharacter() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( !object->flagCharacter()) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetNonPathfinding() - return true if all objects are not pathfinding +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetNonPathfinding() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( object->flagObjectPermanent() || object->flagCharacter()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsNonPathfinding() - return true if all root objects are not +// pathfinding +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsNonPathfinding() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( object->flagObjectPermanent() || object->flagCharacter()) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetNonPermanent() - return true if all objects are not permanent +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetNonPermanent() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( object->flagObjectPermanent()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsNonPermanent() - return true if all root objects are not +// permanent +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsNonPermanent() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( object->flagObjectPermanent()) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +// selectGetNonCharacter() - return true if all objects are not character +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetNonCharacter() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( object->flagCharacter()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsNonCharacter() - return true if all root objects are not +// character +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsNonCharacter() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if( object->flagCharacter()) + { + return false; + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// selectGetEditableLinksets() - return true if all objects are editable +// pathfinding linksets +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetEditableLinksets() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if (object->flagUsePhysics() || + object->flagTemporaryOnRez() || + object->flagCharacter() || + object->flagVolumeDetect() || + object->flagAnimSource() || + (object->getRegion() != gAgent.getRegion()) || + (!gAgent.isGodlike() && + !gAgent.canManageEstate() && + !object->permYouOwner() && + !object->permMove())) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetViewableCharacters() - return true if all objects are characters +// viewable within the pathfinding characters floater +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetViewableCharacters() +{ + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !object || !node->mValid ) + { + return false; + } + if( !object->flagCharacter() || + (object->getRegion() != gAgent.getRegion())) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsTransfer() - return true if current agent can transfer all +// selected root objects. +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsTransfer() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if(!object->permTransfer()) + { + return false; + } + } + return true; +} + +//----------------------------------------------------------------------------- +// selectGetRootsCopy() - return true if current agent can copy all +// selected root objects. +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetRootsCopy() +{ + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if( !node->mValid ) + { + return false; + } + if(!object->permCopy()) + { + return false; + } + } + return true; +} + +struct LLSelectGetFirstTest +{ + LLSelectGetFirstTest() : mIdentical(true), mFirst(true) { } + virtual ~LLSelectGetFirstTest() { } + + // returns false to break out of the iteration. + bool checkMatchingNode(LLSelectNode* node) + { + if (!node || !node->mValid) + { + return false; + } + + if (mFirst) + { + mFirstValue = getValueFromNode(node); + mFirst = false; + } + else + { + if ( mFirstValue != getValueFromNode(node) ) + { + mIdentical = false; + // stop testing once we know not all selected are identical. + return false; + } + } + // continue testing. + return true; + } + + bool mIdentical; + LLUUID mFirstValue; + +protected: + virtual const LLUUID& getValueFromNode(LLSelectNode* node) = 0; + +private: + bool mFirst; +}; + +void LLSelectMgr::getFirst(LLSelectGetFirstTest* test) +{ + if (gSavedSettings.getBOOL("EditLinkedParts")) + { + for (LLObjectSelection::valid_iterator iter = getSelection()->valid_begin(); + iter != getSelection()->valid_end(); ++iter ) + { + if (!test->checkMatchingNode(*iter)) + { + break; + } + } + } + else + { + for (LLObjectSelection::root_object_iterator iter = getSelection()->root_object_begin(); + iter != getSelection()->root_object_end(); ++iter ) + { + if (!test->checkMatchingNode(*iter)) + { + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// selectGetCreator() +// Creator information only applies to roots unless editing linked parts. +//----------------------------------------------------------------------------- +struct LLSelectGetFirstCreator : public LLSelectGetFirstTest +{ +protected: + virtual const LLUUID& getValueFromNode(LLSelectNode* node) + { + return node->mPermissions->getCreator(); + } +}; + +bool LLSelectMgr::selectGetCreator(LLUUID& result_id, std::string& name) +{ + LLSelectGetFirstCreator test; + getFirst(&test); + + if (test.mFirstValue.isNull()) + { + name = LLTrans::getString("AvatarNameNobody"); + return false; + } + + result_id = test.mFirstValue; + + if (test.mIdentical) + { + name = LLSLURL("agent", test.mFirstValue, "inspect").getSLURLString(); + } + else + { + name = LLTrans::getString("AvatarNameMultiple"); + } + + return test.mIdentical; +} + +//----------------------------------------------------------------------------- +// selectGetOwner() +// Owner information only applies to roots unless editing linked parts. +//----------------------------------------------------------------------------- +struct LLSelectGetFirstOwner : public LLSelectGetFirstTest +{ +protected: + virtual const LLUUID& getValueFromNode(LLSelectNode* node) + { + // Don't use 'getOwnership' since we return a reference, not a copy. + // Will return LLUUID::null if unowned (which is not allowed and should never happen.) + return node->mPermissions->isGroupOwned() ? node->mPermissions->getGroup() : node->mPermissions->getOwner(); + } +}; + +bool LLSelectMgr::selectGetOwner(LLUUID& result_id, std::string& name) +{ + LLSelectGetFirstOwner test; + getFirst(&test); + + if (test.mFirstValue.isNull()) + { + return false; + } + + result_id = test.mFirstValue; + + if (test.mIdentical) + { + bool group_owned = selectIsGroupOwned(); + if (group_owned) + { + name = LLSLURL("group", test.mFirstValue, "inspect").getSLURLString(); + } + else + { + name = LLSLURL("agent", test.mFirstValue, "inspect").getSLURLString(); + } + } + else + { + name = LLTrans::getString("AvatarNameMultiple"); + } + + return test.mIdentical; +} + +//----------------------------------------------------------------------------- +// selectGetLastOwner() +// Owner information only applies to roots unless editing linked parts. +//----------------------------------------------------------------------------- +struct LLSelectGetFirstLastOwner : public LLSelectGetFirstTest +{ +protected: + virtual const LLUUID& getValueFromNode(LLSelectNode* node) + { + return node->mPermissions->getLastOwner(); + } +}; + +bool LLSelectMgr::selectGetLastOwner(LLUUID& result_id, std::string& name) +{ + LLSelectGetFirstLastOwner test; + getFirst(&test); + + if (test.mFirstValue.isNull()) + { + return false; + } + + result_id = test.mFirstValue; + + if (test.mIdentical) + { + name = LLSLURL("agent", test.mFirstValue, "inspect").getSLURLString(); + } + else + { + name.assign( "" ); + } + + return test.mIdentical; +} + +//----------------------------------------------------------------------------- +// selectGetGroup() +// Group information only applies to roots unless editing linked parts. +//----------------------------------------------------------------------------- +struct LLSelectGetFirstGroup : public LLSelectGetFirstTest +{ +protected: + virtual const LLUUID& getValueFromNode(LLSelectNode* node) + { + return node->mPermissions->getGroup(); + } +}; + +bool LLSelectMgr::selectGetGroup(LLUUID& result_id) +{ + LLSelectGetFirstGroup test; + getFirst(&test); + + result_id = test.mFirstValue; + return test.mIdentical; +} + +//----------------------------------------------------------------------------- +// selectIsGroupOwned() +// Only operates on root nodes unless editing linked parts. +// Returns true if the first selected is group owned. +//----------------------------------------------------------------------------- +struct LLSelectGetFirstGroupOwner : public LLSelectGetFirstTest +{ +protected: + virtual const LLUUID& getValueFromNode(LLSelectNode* node) + { + if (node->mPermissions->isGroupOwned()) + { + return node->mPermissions->getGroup(); + } + return LLUUID::null; + } +}; + +bool LLSelectMgr::selectIsGroupOwned() +{ + LLSelectGetFirstGroupOwner test; + getFirst(&test); + + return test.mFirstValue.notNull(); +} + +//----------------------------------------------------------------------------- +// selectGetPerm() +// Only operates on root nodes. +// Returns true if all have valid data. +// mask_on has bits set to true where all permissions are true +// mask_off has bits set to true where all permissions are false +// if a bit is off both in mask_on and mask_off, the values differ within +// the selection. +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectGetPerm(U8 which_perm, U32* mask_on, U32* mask_off) +{ + U32 mask; + U32 mask_and = 0xffffffff; + U32 mask_or = 0x00000000; + bool all_valid = false; + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + + if (!node->mValid) + { + all_valid = false; + break; + } + + all_valid = true; + + switch( which_perm ) + { + case PERM_BASE: + mask = node->mPermissions->getMaskBase(); + break; + case PERM_OWNER: + mask = node->mPermissions->getMaskOwner(); + break; + case PERM_GROUP: + mask = node->mPermissions->getMaskGroup(); + break; + case PERM_EVERYONE: + mask = node->mPermissions->getMaskEveryone(); + break; + case PERM_NEXT_OWNER: + mask = node->mPermissions->getMaskNextOwner(); + break; + default: + mask = 0x0; + break; + } + mask_and &= mask; + mask_or |= mask; + } + + if (all_valid) + { + // ...true through all ANDs means all true + *mask_on = mask_and; + + // ...false through all ORs means all false + *mask_off = ~mask_or; + return true; + } + else + { + *mask_on = 0; + *mask_off = 0; + return false; + } +} + + + +bool LLSelectMgr::selectGetPermissions(LLPermissions& result_perm) +{ + bool first = true; + LLPermissions perm; + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + if (!node->mValid) + { + return false; + } + + if (first) + { + perm = *(node->mPermissions); + first = false; + } + else + { + perm.accumulate(*(node->mPermissions)); + } + } + + result_perm = perm; + + return true; +} + + +void LLSelectMgr::selectDelete() +{ + S32 deleteable_count = 0; + + bool locked_but_deleteable_object = false; + bool no_copy_but_deleteable_object = false; + bool all_owned_by_you = true; + + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++) + { + LLViewerObject* obj = (*iter)->getObject(); + + if( obj->isAttachment() ) + { + continue; + } + + deleteable_count++; + + // Check to see if you can delete objects which are locked. + if(!obj->permMove()) + { + locked_but_deleteable_object = true; + } + if(!obj->permCopy()) + { + no_copy_but_deleteable_object = true; + } + if(!obj->permYouOwner()) + { + all_owned_by_you = false; + } + } + + if( 0 == deleteable_count ) + { + make_ui_sound("UISndInvalidOp"); + return; + } + + LLNotification::Params params("ConfirmObjectDeleteLock"); + params.functor.function(boost::bind(&LLSelectMgr::confirmDelete, _1, _2, getSelection())); + + if(locked_but_deleteable_object || + no_copy_but_deleteable_object || + !all_owned_by_you) + { + // convert any transient pie-menu selections to full selection so this operation + // has some context + // NOTE: if user cancels delete operation, this will potentially leave objects selected outside of build mode + // but this is ok, if not ideal + convertTransient(); + + //This is messy, but needed to get all english our of the UI. + if(locked_but_deleteable_object && !no_copy_but_deleteable_object && all_owned_by_you) + { + //Locked only + params.name("ConfirmObjectDeleteLock"); + } + else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you) + { + //No Copy only + params.name("ConfirmObjectDeleteNoCopy"); + } + else if(!locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you) + { + //not owned only + params.name("ConfirmObjectDeleteNoOwn"); + } + else if(locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you) + { + //locked and no copy + params.name("ConfirmObjectDeleteLockNoCopy"); + } + else if(locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you) + { + //locked and not owned + params.name("ConfirmObjectDeleteLockNoOwn"); + } + else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && !all_owned_by_you) + { + //no copy and not owned + params.name("ConfirmObjectDeleteNoCopyNoOwn"); + } + else + { + //locked, no copy and not owned + params.name("ConfirmObjectDeleteLockNoCopyNoOwn"); + } + + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } +} + +// static +bool LLSelectMgr::confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (!handle->getObjectCount()) + { + LL_WARNS() << "Nothing to delete!" << LL_ENDL; + return false; + } + + switch(option) + { + case 0: + { + // TODO: Make sure you have delete permissions on all of them. + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + // attempt to derez into the trash. + LLDeRezInfo info(DRD_TRASH, trash_id); + LLSelectMgr::getInstance()->sendListToRegions("DeRezObject", + packDeRezHeader, + packObjectLocalID, + logNoOp, + (void*) &info, + SEND_ONLY_ROOTS); + // VEFFECT: Delete Object - one effect for all deletes + if (LLSelectMgr::getInstance()->mSelectedObjects->mSelectType != SELECT_TYPE_HUD) + { + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, true); + effectp->setPositionGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal() ); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + F32 duration = 0.5f; + duration += LLSelectMgr::getInstance()->mSelectedObjects->getObjectCount() / 64.f; + effectp->setDuration(duration); + } + + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + + // Keep track of how many objects have been deleted. + add(LLStatViewer::DELETE_OBJECT, LLSelectMgr::getInstance()->mSelectedObjects->getObjectCount()); + } + break; + case 1: + default: + break; + } + return false; +} + + +void LLSelectMgr::selectForceDelete() +{ + sendListToRegions( + "ObjectDelete", + packDeleteHeader, + packObjectLocalID, + logNoOp, + (void*)true, + SEND_ONLY_ROOTS); +} + +bool LLSelectMgr::selectGetEditMoveLinksetPermissions(bool &move, bool &modify) +{ + move = true; + modify = true; + bool selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); + + for (LLObjectSelection::iterator iter = getSelection()->begin(); + iter != getSelection()->end(); iter++) + { + LLSelectNode* nodep = *iter; + LLViewerObject* object = nodep->getObject(); + if (!object || !nodep->mValid) + { + move = false; + modify = false; + return false; + } + + LLViewerObject *root_object = object->getRootEdit(); + bool this_object_movable = false; + if (object->permMove() && !object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced()) && + (object->permModify() || selecting_linked_set)) + { + this_object_movable = true; + } + move = move && this_object_movable; + modify = modify && object->permModify(); + } + + return true; +} + +void LLSelectMgr::selectGetAggregateSaleInfo(U32 &num_for_sale, + bool &is_for_sale_mixed, + bool &is_sale_price_mixed, + S32 &total_sale_price, + S32 &individual_sale_price) +{ + num_for_sale = 0; + is_for_sale_mixed = false; + is_sale_price_mixed = false; + total_sale_price = 0; + individual_sale_price = 0; + + + // Empty set. + if (getSelection()->root_begin() == getSelection()->root_end()) + return; + + LLSelectNode *node = *(getSelection()->root_begin()); + const bool first_node_for_sale = node->mSaleInfo.isForSale(); + const S32 first_node_sale_price = node->mSaleInfo.getSalePrice(); + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + const bool node_for_sale = node->mSaleInfo.isForSale(); + const S32 node_sale_price = node->mSaleInfo.getSalePrice(); + + // Set mixed if the fields don't match the first node's fields. + if (node_for_sale != first_node_for_sale) + is_for_sale_mixed = true; + if (node_sale_price != first_node_sale_price) + is_sale_price_mixed = true; + + if (node_for_sale) + { + total_sale_price += node_sale_price; + num_for_sale ++; + } + } + + individual_sale_price = first_node_sale_price; + if (is_for_sale_mixed) + { + is_sale_price_mixed = true; + individual_sale_price = 0; + } +} + +// returns true if all nodes are valid. method also stores an +// accumulated sale info. +bool LLSelectMgr::selectGetSaleInfo(LLSaleInfo& result_sale_info) +{ + bool first = true; + LLSaleInfo sale_info; + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + if (!node->mValid) + { + return false; + } + + if (first) + { + sale_info = node->mSaleInfo; + first = false; + } + else + { + sale_info.accumulate(node->mSaleInfo); + } + } + + result_sale_info = sale_info; + + return true; +} + +bool LLSelectMgr::selectGetAggregatePermissions(LLAggregatePermissions& result_perm) +{ + bool first = true; + LLAggregatePermissions perm; + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + if (!node->mValid) + { + return false; + } + + if (first) + { + perm = node->mAggregatePerm; + first = false; + } + else + { + perm.aggregate(node->mAggregatePerm); + } + } + + result_perm = perm; + + return true; +} + +bool LLSelectMgr::selectGetAggregateTexturePermissions(LLAggregatePermissions& result_perm) +{ + bool first = true; + LLAggregatePermissions perm; + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + if (!node->mValid) + { + return false; + } + + LLAggregatePermissions t_perm = node->getObject()->permYouOwner() ? node->mAggregateTexturePermOwner : node->mAggregateTexturePerm; + if (first) + { + perm = t_perm; + first = false; + } + else + { + perm.aggregate(t_perm); + } + } + + result_perm = perm; + + return true; +} + +bool LLSelectMgr::isMovableAvatarSelected() +{ + if (mAllowSelectAvatar && getSelection()->getObjectCount() == 1) + { + // nothing but avatar should be selected, so check that + // there is only one selected object and it is a root + LLViewerObject* obj = getSelection()->getFirstRootObject(); + return obj && obj->isAvatar() && getSelection()->getFirstMoveableNode(true); + } + return false; +} + +//-------------------------------------------------------------------- +// Duplicate objects +//-------------------------------------------------------------------- + +// JC - If this doesn't work right, duplicate the selection list +// before doing anything, do a deselect, then send the duplicate +// messages. +struct LLDuplicateData +{ + LLVector3 offset; + U32 flags; +}; + +void LLSelectMgr::selectDuplicate(const LLVector3& offset, bool select_copy) +{ + if (mSelectedObjects->isAttachment()) + { + //RN: do not duplicate attachments + make_ui_sound("UISndInvalidOp"); + return; + } + if (!canDuplicate()) + { + LLSelectNode* node = getSelection()->getFirstRootNode(NULL, true); + if (node) + { + LLSD args; + args["OBJ_NAME"] = node->mName; + LLNotificationsUtil::add("NoCopyPermsNoObject", args); + return; + } + } + LLDuplicateData data; + + data.offset = offset; + data.flags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0); + + sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS); + + if (select_copy) + { + // the new copy will be coming in selected + deselectAll(); + } + else + { + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + node->mDuplicated = true; + node->mDuplicatePos = node->getObject()->getPositionGlobal(); + node->mDuplicateRot = node->getObject()->getRotation(); + } + } +} + +void LLSelectMgr::repeatDuplicate() +{ + if (mSelectedObjects->isAttachment()) + { + //RN: do not duplicate attachments + make_ui_sound("UISndInvalidOp"); + return; + } + + std::vector<LLViewerObject*> non_duplicated_objects; + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + if (!node->mDuplicated) + { + non_duplicated_objects.push_back(node->getObject()); + } + } + + // make sure only previously duplicated objects are selected + for (std::vector<LLViewerObject*>::iterator iter = non_duplicated_objects.begin(); + iter != non_duplicated_objects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + deselectObjectAndFamily(objectp); + } + + // duplicate objects in place + LLDuplicateData data; + + data.offset = LLVector3::zero; + data.flags = 0x0; + + sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS); + + // move current selection based on delta from duplication position and update duplication position + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++ ) + { + LLSelectNode* node = *iter; + if (node->mDuplicated) + { + LLQuaternion cur_rot = node->getObject()->getRotation(); + LLQuaternion rot_delta = (~node->mDuplicateRot * cur_rot); + LLQuaternion new_rot = cur_rot * rot_delta; + LLVector3d cur_pos = node->getObject()->getPositionGlobal(); + LLVector3d new_pos = cur_pos + ((cur_pos - node->mDuplicatePos) * rot_delta); + + node->mDuplicatePos = node->getObject()->getPositionGlobal(); + node->mDuplicateRot = node->getObject()->getRotation(); + node->getObject()->setPositionGlobal(new_pos); + node->getObject()->setRotation(new_rot); + } + } + + sendMultipleUpdate(UPD_ROTATION | UPD_POSITION); +} + +// static +void LLSelectMgr::packDuplicate( LLSelectNode* node, void *duplicate_data ) +{ + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID()); +} + + +//-------------------------------------------------------------------- +// Duplicate On Ray +//-------------------------------------------------------------------- + +// Duplicates the selected objects, but places the copy along a cast +// ray. +struct LLDuplicateOnRayData +{ + LLVector3 mRayStartRegion; + LLVector3 mRayEndRegion; + bool mBypassRaycast; + bool mRayEndIsIntersection; + LLUUID mRayTargetID; + bool mCopyCenters; + bool mCopyRotates; + U32 mFlags; +}; + +void LLSelectMgr::selectDuplicateOnRay(const LLVector3 &ray_start_region, + const LLVector3 &ray_end_region, + bool bypass_raycast, + bool ray_end_is_intersection, + const LLUUID &ray_target_id, + bool copy_centers, + bool copy_rotates, + bool select_copy) +{ + if (mSelectedObjects->isAttachment()) + { + // do not duplicate attachments + make_ui_sound("UISndInvalidOp"); + return; + } + + LLDuplicateOnRayData data; + + data.mRayStartRegion = ray_start_region; + data.mRayEndRegion = ray_end_region; + data.mBypassRaycast = bypass_raycast; + data.mRayEndIsIntersection = ray_end_is_intersection; + data.mRayTargetID = ray_target_id; + data.mCopyCenters = copy_centers; + data.mCopyRotates = copy_rotates; + data.mFlags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0); + + sendListToRegions("ObjectDuplicateOnRay", + packDuplicateOnRayHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS); + + if (select_copy) + { + // the new copy will be coming in selected + deselectAll(); + } +} + +// static +void LLSelectMgr::packDuplicateOnRayHead(void *user_data) +{ + LLMessageSystem *msg = gMessageSystem; + LLDuplicateOnRayData *data = (LLDuplicateOnRayData *)user_data; + + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); + msg->addVector3Fast(_PREHASH_RayStart, data->mRayStartRegion ); + msg->addVector3Fast(_PREHASH_RayEnd, data->mRayEndRegion ); + msg->addBOOLFast(_PREHASH_BypassRaycast, data->mBypassRaycast ); + msg->addBOOLFast(_PREHASH_RayEndIsIntersection, data->mRayEndIsIntersection ); + msg->addBOOLFast(_PREHASH_CopyCenters, data->mCopyCenters ); + msg->addBOOLFast(_PREHASH_CopyRotates, data->mCopyRotates ); + msg->addUUIDFast(_PREHASH_RayTargetID, data->mRayTargetID ); + msg->addU32Fast(_PREHASH_DuplicateFlags, data->mFlags ); +} + + + +//------------------------------------------------------------------------ +// Object position, scale, rotation update, all-in-one +//------------------------------------------------------------------------ + +void LLSelectMgr::sendMultipleUpdate(U32 type) +{ + if (type == UPD_NONE) return; + // send individual updates when selecting textures or individual objects + ESendType send_type = (!gSavedSettings.getBOOL("EditLinkedParts") && !getTEMode()) ? SEND_ONLY_ROOTS : SEND_ROOTS_FIRST; + if (send_type == SEND_ONLY_ROOTS) + { + // tell simulator to apply to whole linked sets + type |= UPD_LINKED_SETS; + } + + sendListToRegions( + "MultipleObjectUpdate", + packAgentAndSessionID, + packMultipleUpdate, + logNoOp, + &type, + send_type); +} + +// static +void LLSelectMgr::packMultipleUpdate(LLSelectNode* node, void *user_data) +{ + LLViewerObject* object = node->getObject(); + U32 *type32 = (U32 *)user_data; + U8 type = (U8)*type32; + U8 data[256]; + + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() ); + gMessageSystem->addU8Fast(_PREHASH_Type, type ); + + S32 offset = 0; + + // JC: You MUST pack the data in this order. The receiving + // routine process_multiple_update_message on simulator will + // extract them in this order. + + if (type & UPD_POSITION) + { + htolememcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12); + offset += 12; + } + if (type & UPD_ROTATION) + { + LLQuaternion quat = object->getRotation(); + LLVector3 vec = quat.packToVector3(); + htolememcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12); + offset += 12; + } + if (type & UPD_SCALE) + { + //LL_INFOS() << "Sending object scale " << object->getScale() << LL_ENDL; + htolememcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12); + offset += 12; + } + gMessageSystem->addBinaryDataFast(_PREHASH_Data, data, offset); +} + +//------------------------------------------------------------------------ +// Ownership +//------------------------------------------------------------------------ +struct LLOwnerData +{ + LLUUID owner_id; + LLUUID group_id; + bool override; +}; + +void LLSelectMgr::sendOwner(const LLUUID& owner_id, + const LLUUID& group_id, + bool override) +{ + LLOwnerData data; + + data.owner_id = owner_id; + data.group_id = group_id; + data.override = override; + + sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS); +} + +// static +void LLSelectMgr::packOwnerHead(void *user_data) +{ + LLOwnerData *data = (LLOwnerData *)user_data; + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + gMessageSystem->nextBlockFast(_PREHASH_HeaderData); + gMessageSystem->addBOOLFast(_PREHASH_Override, data->override); + gMessageSystem->addUUIDFast(_PREHASH_OwnerID, data->owner_id); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, data->group_id); +} + +//------------------------------------------------------------------------ +// Group +//------------------------------------------------------------------------ + +void LLSelectMgr::sendGroup(const LLUUID& group_id) +{ + LLUUID local_group_id(group_id); + sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, logNoOp, &local_group_id, SEND_ONLY_ROOTS); +} + + +//------------------------------------------------------------------------ +// Buy +//------------------------------------------------------------------------ + +struct LLBuyData +{ + std::vector<LLViewerObject*> mObjectsSent; + LLUUID mCategoryID; + LLSaleInfo mSaleInfo; +}; + +// *NOTE: does not work for multiple object buy, which UI does not +// currently support sale info is used for verification only, if it +// doesn't match region info then sale is canceled Need to get sale +// info -as displayed in the UI- for every item. +void LLSelectMgr::sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info) +{ + LLBuyData buy; + buy.mCategoryID = category_id; + buy.mSaleInfo = sale_info; + sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, logNoOp, &buy, SEND_ONLY_ROOTS); +} + +// static +void LLSelectMgr::packBuyObjectIDs(LLSelectNode* node, void* data) +{ + LLBuyData* buy = (LLBuyData*)data; + + LLViewerObject* object = node->getObject(); + if (std::find(buy->mObjectsSent.begin(), buy->mObjectsSent.end(), object) == buy->mObjectsSent.end()) + { + buy->mObjectsSent.push_back(object); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() ); + gMessageSystem->addU8Fast(_PREHASH_SaleType, buy->mSaleInfo.getSaleType()); + gMessageSystem->addS32Fast(_PREHASH_SalePrice, buy->mSaleInfo.getSalePrice()); + } +} + +//------------------------------------------------------------------------ +// Permissions +//------------------------------------------------------------------------ + +struct LLPermData +{ + U8 mField; + bool mSet; + U32 mMask; + bool mOverride; +}; + +// TODO: Make this able to fail elegantly. +void LLSelectMgr::selectionSetObjectPermissions(U8 field, + bool set, + U32 mask, + bool override) +{ + LLPermData data; + + data.mField = field; + data.mSet = set; + data.mMask = mask; + data.mOverride = override; + + sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, logNoOp, &data, SEND_ONLY_ROOTS); +} + +void LLSelectMgr::packPermissionsHead(void* user_data) +{ + LLPermData* data = (LLPermData*)user_data; + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_HeaderData); + gMessageSystem->addBOOLFast(_PREHASH_Override, data->mOverride); +} + + +// Now that you've added a bunch of objects, send a select message +// on the entire list for efficiency. +/* +void LLSelectMgr::sendSelect() +{ + LL_ERRS() << "Not implemented" << LL_ENDL; +} +*/ + +void LLSelectMgr::deselectAll() +{ + if (!mSelectedObjects->getNumNodes()) + { + return; + } + + // Zap the angular velocity, as the sim will set it to zero + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++ ) + { + LLViewerObject *objectp = (*iter)->getObject(); + objectp->setAngularVelocity( 0,0,0 ); + objectp->setVelocity( 0,0,0 ); + } + + sendListToRegions( + "ObjectDeselect", + packAgentAndSessionID, + packObjectLocalID, + logNoOp, + NULL, + SEND_INDIVIDUALS); + + removeAll(); + + mLastSentSelectionCenterGlobal.clearVec(); + + updatePointAt(); +} + +void LLSelectMgr::deselectAllForStandingUp() +{ + /* + This function is similar deselectAll() except for the first if statement + which was removed. This is needed as a workaround for DEV-2854 + */ + + // Zap the angular velocity, as the sim will set it to zero + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++ ) + { + LLViewerObject *objectp = (*iter)->getObject(); + objectp->setAngularVelocity( 0,0,0 ); + objectp->setVelocity( 0,0,0 ); + } + + sendListToRegions( + "ObjectDeselect", + packAgentAndSessionID, + packObjectLocalID, + logNoOp, + NULL, + SEND_INDIVIDUALS); + + removeAll(); + + mLastSentSelectionCenterGlobal.clearVec(); + + updatePointAt(); +} + +void LLSelectMgr::deselectUnused() +{ + // no more outstanding references to this selection + if (mSelectedObjects->getNumRefs() == 1) + { + deselectAll(); + } +} + +void LLSelectMgr::convertTransient() +{ + LLObjectSelection::iterator node_it; + for (node_it = mSelectedObjects->begin(); node_it != mSelectedObjects->end(); ++node_it) + { + LLSelectNode *nodep = *node_it; + nodep->setTransient(false); + } +} + +void LLSelectMgr::deselectAllIfTooFar() +{ + if (mSelectedObjects->isEmpty() || mSelectedObjects->mSelectType == SELECT_TYPE_HUD) + { + return; + } + + // HACK: Don't deselect when we're navigating to rate an object's + // owner or creator. JC + if (gMenuObject->getVisible()) + { + return; + } + + LLVector3d selectionCenter = getSelectionCenterGlobal(); + if (gSavedSettings.getBOOL("LimitSelectDistance") + && (!mSelectedObjects->getPrimaryObject() || !mSelectedObjects->getPrimaryObject()->isAvatar()) + && (mSelectedObjects->getPrimaryObject() != LLViewerMediaFocus::getInstance()->getFocusedObject()) + && !mSelectedObjects->isAttachment() + && !selectionCenter.isExactlyZero()) + { + F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance"); + F32 deselect_dist_sq = deselect_dist * deselect_dist; + + LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter; + F32 select_dist_sq = (F32) select_delta.magVecSquared(); + + if (select_dist_sq > deselect_dist_sq) + { + if (mDebugSelectMgr) + { + LL_INFOS() << "Selection manager: auto-deselecting, select_dist = " << (F32) sqrt(select_dist_sq) << LL_ENDL; + LL_INFOS() << "agent pos global = " << gAgent.getPositionGlobal() << LL_ENDL; + LL_INFOS() << "selection pos global = " << selectionCenter << LL_ENDL; + } + + deselectAll(); + } + } +} + + +void LLSelectMgr::selectionSetObjectName(const std::string& name) +{ + std::string name_copy(name); + + // we only work correctly if 1 object is selected. + if(mSelectedObjects->getRootObjectCount() == 1) + { + sendListToRegions("ObjectName", + packAgentAndSessionID, + packObjectName, + logNoOp, + (void*)(&name_copy), + SEND_ONLY_ROOTS); + } + else if(mSelectedObjects->getObjectCount() == 1) + { + sendListToRegions("ObjectName", + packAgentAndSessionID, + packObjectName, + logNoOp, + (void*)(&name_copy), + SEND_INDIVIDUALS); + } +} + +void LLSelectMgr::selectionSetObjectDescription(const std::string& desc) +{ + std::string desc_copy(desc); + + // we only work correctly if 1 object is selected. + if(mSelectedObjects->getRootObjectCount() == 1) + { + sendListToRegions("ObjectDescription", + packAgentAndSessionID, + packObjectDescription, + logNoOp, + (void*)(&desc_copy), + SEND_ONLY_ROOTS); + } + else if(mSelectedObjects->getObjectCount() == 1) + { + sendListToRegions("ObjectDescription", + packAgentAndSessionID, + packObjectDescription, + logNoOp, + (void*)(&desc_copy), + SEND_INDIVIDUALS); + } +} + +void LLSelectMgr::selectionSetObjectCategory(const LLCategory& category) +{ + // for now, we only want to be able to set one root category at + // a time. + if(mSelectedObjects->getRootObjectCount() != 1) return; + sendListToRegions("ObjectCategory", + packAgentAndSessionID, + packObjectCategory, + logNoOp, + (void*)(&category), + SEND_ONLY_ROOTS); +} + +void LLSelectMgr::selectionSetObjectSaleInfo(const LLSaleInfo& sale_info) +{ + sendListToRegions("ObjectSaleInfo", + packAgentAndSessionID, + packObjectSaleInfo, + logNoOp, + (void*)(&sale_info), + SEND_ONLY_ROOTS); +} + +//---------------------------------------------------------------------- +// Attachments +//---------------------------------------------------------------------- + +void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) +{ + sendAttach(mSelectedObjects, attachment_point, replace); +} + +void LLSelectMgr::sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace) +{ + if (selection_handle.isNull()) + { + return; + } + + LLViewerObject* attach_object = selection_handle->getFirstRootObject(); + + if (!attach_object || !isAgentAvatarValid() || selection_handle->mSelectType != SELECT_TYPE_WORLD) + { + return; + } + + bool build_mode = LLToolMgr::getInstance()->inEdit(); + // Special case: Attach to default location for this object. + if (0 == attachment_point || + get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)attachment_point, (LLViewerJointAttachment*)NULL)) + { + if (!replace || attachment_point != 0) + { + // If we know the attachment point then we got here by clicking an + // "Attach to..." context menu item, so we should add, not replace. + attachment_point |= ATTACHMENT_ADD; + } + + sendListToRegions( + selection_handle, + "ObjectAttach", + packAgentIDAndSessionAndAttachment, + packObjectIDAndRotation, + logAttachmentRequest, + &attachment_point, + SEND_ONLY_ROOTS ); + if (!build_mode) + { + // After "ObjectAttach" server will unsubscribe us from properties updates + // so either deselect objects or resend selection after attach packet reaches server + // In case of build_mode LLPanelObjectInventory::refresh() will deal with selection + // Still unsubscribe even in case selection_handle is not current selection + deselectAll(); + } + } +} + +void LLSelectMgr::sendDetach() +{ + if (!mSelectedObjects->getNumNodes() || mSelectedObjects->mSelectType == SELECT_TYPE_WORLD) + { + return; + } + + sendListToRegions( + "ObjectDetach", + packAgentAndSessionID, + packObjectLocalID, + logDetachRequest, + NULL, + SEND_ONLY_ROOTS ); +} + + +void LLSelectMgr::sendDropAttachment() +{ + if (!mSelectedObjects->getNumNodes() || mSelectedObjects->mSelectType == SELECT_TYPE_WORLD) + { + return; + } + + sendListToRegions( + "ObjectDrop", + packAgentAndSessionID, + packObjectLocalID, + logDetachRequest, + NULL, + SEND_ONLY_ROOTS); +} + +//---------------------------------------------------------------------- +// Links +//---------------------------------------------------------------------- + +void LLSelectMgr::sendLink() +{ + if (!mSelectedObjects->getNumNodes()) + { + return; + } + + sendListToRegions( + "ObjectLink", + packAgentAndSessionID, + packObjectLocalID, + logNoOp, + NULL, + SEND_ONLY_ROOTS); +} + +void LLSelectMgr::sendDelink() +{ + if (!mSelectedObjects->getNumNodes()) + { + return; + } + + struct f : public LLSelectedObjectFunctor + { //on delink, any modifyable object should + f() {} + + virtual bool apply(LLViewerObject* object) + { + if (object->permModify()) + { + if (object->getPhysicsShapeType() == LLViewerObject::PHYSICS_SHAPE_NONE) + { + object->setPhysicsShapeType(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); + object->updateFlags(); + } + } + return true; + } + } sendfunc; + getSelection()->applyToObjects(&sendfunc); + + + // Delink needs to send individuals so you can unlink a single object from + // a linked set. + sendListToRegions( + "ObjectDelink", + packAgentAndSessionID, + packObjectLocalID, + logNoOp, + NULL, + SEND_INDIVIDUALS); +} + + +//---------------------------------------------------------------------- +// Hinges +//---------------------------------------------------------------------- + +/* +void LLSelectMgr::sendHinge(U8 type) +{ + if (!mSelectedObjects->getNumNodes()) + { + return; + } + + sendListToRegions( + "ObjectHinge", + packHingeHead, + packObjectLocalID, + &type, + SEND_ONLY_ROOTS); +} + + +void LLSelectMgr::sendDehinge() +{ + if (!mSelectedObjects->getNumNodes()) + { + return; + } + + sendListToRegions( + "ObjectDehinge", + packAgentAndSessionID, + packObjectLocalID, + NULL, + SEND_ONLY_ROOTS); +}*/ + +void LLSelectMgr::sendSelect() +{ + if (!mSelectedObjects->getNumNodes()) + { + return; + } + + sendListToRegions( + "ObjectSelect", + packAgentAndSessionID, + packObjectLocalID, + logNoOp, + NULL, + SEND_INDIVIDUALS); +} + +// static +void LLSelectMgr::packHingeHead(void *user_data) +{ + U8 *type = (U8 *)user_data; + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + gMessageSystem->nextBlockFast(_PREHASH_JointType); + gMessageSystem->addU8Fast(_PREHASH_Type, *type ); +} + + +void LLSelectMgr::selectionDump() +{ + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + object->dump(); + return true; + } + } func; + getSelection()->applyToObjects(&func); +} + +void LLSelectMgr::saveSelectedObjectColors() +{ + struct f : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* node) + { + node->saveColors(); + return true; + } + } func; + getSelection()->applyToNodes(&func); +} + +void LLSelectMgr::saveSelectedShinyColors() +{ + struct f : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* node) + { + node->saveShinyColors(); + return true; + } + } func; + getSelection()->applyToNodes(&func); +} + +void LLSelectMgr::saveSelectedObjectTextures() +{ + // invalidate current selection so we update saved textures + struct f : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* node) + { + node->mValid = false; + return true; + } + } func; + getSelection()->applyToNodes(&func); + + // request object properties message to get updated permissions data + sendSelect(); +} + + +// This routine should be called whenever a drag is initiated. +// also need to know to which simulator to send update message +void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type) +{ + if (mSelectedObjects->isEmpty()) + { + // nothing selected, so nothing to save + return; + } + + struct f : public LLSelectedNodeFunctor + { + EActionType mActionType; + LLSelectMgr* mManager; + f(EActionType a, LLSelectMgr* p) : mActionType(a), mManager(p) {} + virtual bool apply(LLSelectNode* selectNode) + { + LLViewerObject* object = selectNode->getObject(); + if (!object) + { + return true; // skip + } + selectNode->mSavedPositionLocal = object->getPosition(); + if (object->isAttachment()) + { + if (object->isRootEdit()) + { + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + if (parent_xform) + { + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + } + } + else + { + LLViewerObject* attachment_root = (LLViewerObject*)object->getParent(); + LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL; + if (parent_xform) + { + LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation()); + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + } + } + selectNode->mSavedRotation = object->getRenderRotation(); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + selectNode->mSavedRotation = object->getRotationRegion(); + } + + selectNode->mSavedScale = object->getScale(); + selectNode->saveTextureScaleRatios(mManager->mTextureChannel); + return true; + } + } func(action_type, this); + getSelection()->applyToNodes(&func); + + mSavedSelectionBBox = getBBoxOfSelection(); +} + +struct LLSelectMgrApplyFlags : public LLSelectedObjectFunctor +{ + LLSelectMgrApplyFlags(U32 flags, bool state) : mFlags(flags), mState(state) {} + U32 mFlags; + bool mState; + virtual bool apply(LLViewerObject* object) + { + if ( object->permModify()) + { + if (object->isRoot()) // don't send for child objects + { + object->setFlags( mFlags, mState); + } + else if (FLAGS_WORLD & mFlags && ((LLViewerObject*)object->getRoot())->isSelected()) + { + // FLAGS_WORLD are shared by all items in linkset + object->setFlagsWithoutUpdate(FLAGS_WORLD & mFlags, mState); + } + }; + return true; + } +}; + +void LLSelectMgr::selectionUpdatePhysics(bool physics) +{ + LLSelectMgrApplyFlags func( FLAGS_USE_PHYSICS, physics); + getSelection()->applyToObjects(&func); +} + +void LLSelectMgr::selectionUpdateTemporary(bool is_temporary) +{ + LLSelectMgrApplyFlags func( FLAGS_TEMPORARY_ON_REZ, is_temporary); + getSelection()->applyToObjects(&func); +} + +void LLSelectMgr::selectionUpdatePhantom(bool is_phantom) +{ + LLSelectMgrApplyFlags func( FLAGS_PHANTOM, is_phantom); + getSelection()->applyToObjects(&func); +} + +//---------------------------------------------------------------------- +// Helpful packing functions for sendObjectMessage() +//---------------------------------------------------------------------- + +// static +void LLSelectMgr::packAgentIDAndSessionAndAttachment( void *user_data) +{ + U8 *attachment_point = (U8*)user_data; + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addU8Fast(_PREHASH_AttachmentPoint, *attachment_point); +} + +// static +void LLSelectMgr::packAgentID( void *user_data) +{ + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); +} + +// static +void LLSelectMgr::packAgentAndSessionID(void* user_data) +{ + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +} + +// static +void LLSelectMgr::packAgentAndGroupID(void* user_data) +{ + LLOwnerData *data = (LLOwnerData *)user_data; + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, data->owner_id ); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, data->group_id ); +} + +// static +void LLSelectMgr::packAgentAndSessionAndGroupID(void* user_data) +{ + LLUUID* group_idp = (LLUUID*) user_data; + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, *group_idp); +} + +// static +void LLSelectMgr::packDuplicateHeader(void* data) +{ + LLUUID group_id(gAgent.getGroupID()); + packAgentAndSessionAndGroupID(&group_id); + + LLDuplicateData* dup_data = (LLDuplicateData*) data; + + gMessageSystem->nextBlockFast(_PREHASH_SharedData); + gMessageSystem->addVector3Fast(_PREHASH_Offset, dup_data->offset); + gMessageSystem->addU32Fast(_PREHASH_DuplicateFlags, dup_data->flags); +} + +// static +void LLSelectMgr::packDeleteHeader(void* userdata) +{ + bool force = (bool)(intptr_t)userdata; + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addBOOLFast(_PREHASH_Force, force); +} + +// static +void LLSelectMgr::packAgentGroupAndCatID(void* user_data) +{ + LLBuyData* buy = (LLBuyData*)user_data; + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + gMessageSystem->addUUIDFast(_PREHASH_CategoryID, buy->mCategoryID); +} + +//static +void LLSelectMgr::packDeRezHeader(void* user_data) +{ + LLDeRezInfo* info = (LLDeRezInfo*)user_data; + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_AgentBlock); + gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + gMessageSystem->addU8Fast(_PREHASH_Destination, (U8)info->mDestination); + gMessageSystem->addUUIDFast(_PREHASH_DestinationID, info->mDestinationID); + LLUUID tid; + tid.generate(); + gMessageSystem->addUUIDFast(_PREHASH_TransactionID, tid); + const U8 PACKET = 1; + gMessageSystem->addU8Fast(_PREHASH_PacketCount, PACKET); + gMessageSystem->addU8Fast(_PREHASH_PacketNumber, PACKET); +} + +// static +void LLSelectMgr::packObjectID(LLSelectNode* node, void *user_data) +{ + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addUUIDFast(_PREHASH_ObjectID, node->getObject()->mID ); +} + +void LLSelectMgr::packObjectIDAndRotation(LLSelectNode* node, void *user_data) +{ + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() ); + gMessageSystem->addQuatFast(_PREHASH_Rotation, node->getObject()->getRotation()); +} + +void LLSelectMgr::packObjectClickAction(LLSelectNode* node, void *user_data) +{ + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() ); + gMessageSystem->addU8("ClickAction", node->getObject()->getClickAction()); +} + +void LLSelectMgr::packObjectIncludeInSearch(LLSelectNode* node, void *user_data) +{ + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() ); + gMessageSystem->addBOOL("IncludeInSearch", node->getObject()->getIncludeInSearch()); +} + +// static +void LLSelectMgr::packObjectLocalID(LLSelectNode* node, void *) +{ + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID()); +} + +// static +void LLSelectMgr::packObjectName(LLSelectNode* node, void* user_data) +{ + const std::string* name = (const std::string*)user_data; + if(!name->empty()) + { + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID()); + gMessageSystem->addStringFast(_PREHASH_Name, *name); + } +} + +// static +void LLSelectMgr::packObjectDescription(LLSelectNode* node, void* user_data) +{ + const std::string* desc = (const std::string*)user_data; + if(desc) + { // Empty (non-null, but zero length) descriptions are OK + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID()); + gMessageSystem->addStringFast(_PREHASH_Description, *desc); + } +} + +// static +void LLSelectMgr::packObjectCategory(LLSelectNode* node, void* user_data) +{ + LLCategory* category = (LLCategory*)user_data; + if(!category) return; + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID()); + category->packMessage(gMessageSystem); +} + +// static +void LLSelectMgr::packObjectSaleInfo(LLSelectNode* node, void* user_data) +{ + LLSaleInfo* sale_info = (LLSaleInfo*)user_data; + if(!sale_info) return; + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID()); + sale_info->packMessage(gMessageSystem); +} + +// static +void LLSelectMgr::packPhysics(LLSelectNode* node, void *user_data) +{ +} + +// static +void LLSelectMgr::packShape(LLSelectNode* node, void *user_data) +{ +} + +// static +void LLSelectMgr::packPermissions(LLSelectNode* node, void *user_data) +{ + LLPermData *data = (LLPermData *)user_data; + + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID()); + + gMessageSystem->addU8Fast(_PREHASH_Field, data->mField); + gMessageSystem->addBOOLFast(_PREHASH_Set, data->mSet); + gMessageSystem->addU32Fast(_PREHASH_Mask, data->mMask); +} + +// Utility function to send some information to every region containing +// an object on the selection list. We want to do this to reduce the total +// number of packets sent by the viewer. +void LLSelectMgr::sendListToRegions(const std::string& message_name, + void (*pack_header)(void *user_data), + void (*pack_body)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), + void *user_data, + ESendType send_type) +{ + sendListToRegions(mSelectedObjects, message_name, pack_header, pack_body, log_func, user_data, send_type); +} +void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle, + const std::string& message_name, + void (*pack_header)(void *user_data), + void (*pack_body)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), + void *user_data, + ESendType send_type) +{ + LLSelectNode* node; + LLSelectNode* linkset_root = NULL; + LLViewerRegion* last_region; + LLViewerRegion* current_region; + S32 objects_in_this_packet = 0; + + bool link_operation = message_name == "ObjectLink"; + + if (mAllowSelectAvatar) + { + if (selected_handle->getObjectCount() == 1 + && selected_handle->getFirstObject() != NULL + && selected_handle->getFirstObject()->isAvatar()) + { + // Server doesn't move avatars at the moment, it is a local debug feature, + // but server does update position regularly, so do not drop mLastPositionLocal + // Position override for avatar gets reset in LLAgentCamera::resetView(). + } + else + { + // drop mLastPositionLocal (allow next update through) + resetObjectOverrides(selected_handle); + } + } + else + { + //clear update override data (allow next update through) + resetObjectOverrides(selected_handle); + } + + std::queue<LLSelectNode*> nodes_to_send; + + struct push_all : public LLSelectedNodeFunctor + { + std::queue<LLSelectNode*>& nodes_to_send; + push_all(std::queue<LLSelectNode*>& n) : nodes_to_send(n) {} + virtual bool apply(LLSelectNode* node) + { + if (node->getObject()) + { + nodes_to_send.push(node); + } + return true; + } + }; + struct push_some : public LLSelectedNodeFunctor + { + std::queue<LLSelectNode*>& nodes_to_send; + bool mRoots; + push_some(std::queue<LLSelectNode*>& n, bool roots) : nodes_to_send(n), mRoots(roots) {} + virtual bool apply(LLSelectNode* node) + { + if (node->getObject()) + { + bool is_root = node->getObject()->isRootEdit(); + if ((mRoots && is_root) || (!mRoots && !is_root)) + { + nodes_to_send.push(node); + } + } + return true; + } + }; + struct push_all pushall(nodes_to_send); + struct push_some pushroots(nodes_to_send, true); + struct push_some pushnonroots(nodes_to_send, false); + + switch(send_type) + { + case SEND_ONLY_ROOTS: + if(message_name == "ObjectBuy") + selected_handle->applyToRootNodes(&pushroots); + else + selected_handle->applyToRootNodes(&pushall); + + break; + case SEND_INDIVIDUALS: + selected_handle->applyToNodes(&pushall); + break; + case SEND_ROOTS_FIRST: + // first roots... + selected_handle->applyToNodes(&pushroots); + // then children... + selected_handle->applyToNodes(&pushnonroots); + break; + case SEND_CHILDREN_FIRST: + // first children... + selected_handle->applyToNodes(&pushnonroots); + // then roots... + selected_handle->applyToNodes(&pushroots); + break; + + default: + LL_ERRS() << "Bad send type " << send_type << " passed to SendListToRegions()" << LL_ENDL; + } + + // bail if nothing selected + if (nodes_to_send.empty()) + { + return; + } + + node = nodes_to_send.front(); + nodes_to_send.pop(); + + // cache last region information + current_region = node->getObject()->getRegion(); + + // Start duplicate message + // CRO: this isn't + gMessageSystem->newMessage(message_name.c_str()); + (*pack_header)(user_data); + + // For each object + while (node != NULL) + { + // remember the last region, look up the current one + last_region = current_region; + current_region = node->getObject()->getRegion(); + + // if to same simulator and message not too big + if ((current_region == last_region) + && (! gMessageSystem->isSendFull(NULL)) + && (objects_in_this_packet < MAX_OBJECTS_PER_PACKET)) + { + if (link_operation && linkset_root == NULL) + { + // linksets over 254 will be split into multiple messages, + // but we need to provide same root for all messages or we will get separate linksets + linkset_root = node; + } + // add another instance of the body of the data + (*pack_body)(node, user_data); + // do any related logging + (*log_func)(node, user_data); + ++objects_in_this_packet; + + // and on to the next object + if(nodes_to_send.empty()) + { + node = NULL; + } + else + { + node = nodes_to_send.front(); + nodes_to_send.pop(); + } + } + else + { + // otherwise send current message and start new one + gMessageSystem->sendReliable( last_region->getHost()); + objects_in_this_packet = 0; + + gMessageSystem->newMessage(message_name.c_str()); + (*pack_header)(user_data); + + if (linkset_root != NULL) + { + if (current_region != last_region) + { + // root should be in one region with the child, reset it + linkset_root = NULL; + } + else + { + // add root instance into new message + (*pack_body)(linkset_root, user_data); + ++objects_in_this_packet; + } + } + + // don't move to the next object, we still need to add the + // body data. + } + } + + // flush messages + if (gMessageSystem->getCurrentSendTotal() > 0) + { + gMessageSystem->sendReliable( current_region->getHost()); + } + else + { + gMessageSystem->clearMessage(); + } + + // LL_INFOS() << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << LL_ENDL; +} + + +// +// Network communications +// + +void LLSelectMgr::requestObjectPropertiesFamily(LLViewerObject* object) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_RequestFlags, 0x0 ); + msg->addUUIDFast(_PREHASH_ObjectID, object->mID ); + + LLViewerRegion* regionp = object->getRegion(); + msg->sendReliable( regionp->getHost() ); +} + + +// static +void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data) +{ + S32 i; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (i = 0; i < count; i++) + { + LLUUID id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, id, i); + + LLUUID creator_id; + LLUUID owner_id; + LLUUID group_id; + LLUUID last_owner_id; + U64 creation_date; + LLUUID extra_id; + U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask; + LLSaleInfo sale_info; + LLCategory category; + LLAggregatePermissions ag_perms; + LLAggregatePermissions ag_texture_perms; + LLAggregatePermissions ag_texture_perms_owner; + + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_CreatorID, creator_id, i); + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, i); + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id, i); + msg->getU64Fast(_PREHASH_ObjectData, _PREHASH_CreationDate, creation_date, i); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, base_mask, i); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, owner_mask, i); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_GroupMask, group_mask, i); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, everyone_mask, i); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, next_owner_mask, i); + sale_info.unpackMultiMessage(msg, _PREHASH_ObjectData, i); + + ag_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePerms, i); + ag_texture_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTextures, i); + ag_texture_perms_owner.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTexturesOwner, i); + category.unpackMultiMessage(msg, _PREHASH_ObjectData, i); + + S16 inv_serial = 0; + msg->getS16Fast(_PREHASH_ObjectData, _PREHASH_InventorySerial, inv_serial, i); + + LLUUID item_id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ItemID, item_id, i); + LLUUID folder_id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FolderID, folder_id, i); + LLUUID from_task_id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FromTaskID, from_task_id, i); + + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, last_owner_id, i); + + std::string name; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, name, i); + std::string desc; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, desc, i); + + std::string touch_name; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_TouchName, touch_name, i); + std::string sit_name; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_SitName, sit_name, i); + + //unpack TE IDs + uuid_vec_t texture_ids; + S32 size = msg->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_TextureID); + if (size > 0) + { + S8 packed_buffer[SELECT_MAX_TES * UUID_BYTES]; + msg->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureID, packed_buffer, 0, i, SELECT_MAX_TES * UUID_BYTES); + + for (S32 buf_offset = 0; buf_offset < size; buf_offset += UUID_BYTES) + { + LLUUID tid; + memcpy(tid.mData, packed_buffer + buf_offset, UUID_BYTES); /* Flawfinder: ignore */ + texture_ids.push_back(tid); + } + } + + + // Iterate through nodes at end, since it can be on both the regular AND hover list + struct f : public LLSelectedNodeFunctor + { + LLUUID mID; + f(const LLUUID& id) : mID(id) {} + virtual bool apply(LLSelectNode* node) + { + return (node->getObject() && node->getObject()->mID == mID); + } + } func(id); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func); + + if (!node) + { + LL_WARNS() << "Couldn't find object " << id << " selected." << LL_ENDL; + } + else + { + // save texture data as soon as we get texture perms first time + bool save_textures = !node->mValid; + if (node->mInventorySerial != inv_serial && node->getObject()) + { + node->getObject()->dirtyInventory(); + + // Even if this isn't object's first udpate, inventory changed + // and some of the applied textures might have been in inventory + // so update texture list. + save_textures = true; + } + + if (save_textures) + { + bool can_copy = false; + bool can_transfer = false; + + LLAggregatePermissions::EValue value = LLAggregatePermissions::AP_NONE; + if(node->getObject()->permYouOwner()) + { + value = ag_texture_perms_owner.getValue(PERM_COPY); + if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL) + { + can_copy = true; + } + value = ag_texture_perms_owner.getValue(PERM_TRANSFER); + if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL) + { + can_transfer = true; + } + } + else + { + value = ag_texture_perms.getValue(PERM_COPY); + if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL) + { + can_copy = true; + } + value = ag_texture_perms.getValue(PERM_TRANSFER); + if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL) + { + can_transfer = true; + } + } + + if (can_copy && can_transfer) + { + node->saveTextures(texture_ids); + } + + if (can_copy && can_transfer && node->getObject()->getVolume()) + { + uuid_vec_t material_ids; + gltf_materials_vec_t override_materials; + LLVOVolume* vobjp = (LLVOVolume*)node->getObject(); + for (int i = 0; i < vobjp->getNumTEs(); ++i) + { + material_ids.push_back(vobjp->getRenderMaterialID(i)); + + // Make a copy to ensure we won't affect live material + // with any potential changes nor live changes will be + // reflected in a saved copy. + // Like changes from local material (reuses pointer) or + // from live editor (revert mechanics might modify this) + LLGLTFMaterial* old_override = node->getObject()->getTE(i)->getGLTFMaterialOverride(); + if (old_override) + { + LLPointer<LLGLTFMaterial> mat = new LLGLTFMaterial(*old_override); + override_materials.push_back(mat); + } + else + { + override_materials.push_back(nullptr); + } + } + // processObjectProperties does not include overrides so this + // might need to be moved to LLGLTFMaterialOverrideDispatchHandler + node->saveGLTFMaterials(material_ids, override_materials); + } + } + + node->mValid = true; + node->mPermissions->init(creator_id, owner_id, + last_owner_id, group_id); + node->mPermissions->initMasks(base_mask, owner_mask, everyone_mask, group_mask, next_owner_mask); + node->mCreationDate = creation_date; + node->mItemID = item_id; + node->mFolderID = folder_id; + node->mFromTaskID = from_task_id; + node->mName.assign(name); + node->mDescription.assign(desc); + node->mSaleInfo = sale_info; + node->mAggregatePerm = ag_perms; + node->mAggregateTexturePerm = ag_texture_perms; + node->mAggregateTexturePermOwner = ag_texture_perms_owner; + node->mCategory = category; + node->mInventorySerial = inv_serial; + node->mSitName.assign(sit_name); + node->mTouchName.assign(touch_name); + } + } + + dialog_refresh_all(); + + // hack for left-click buy object + LLToolPie::selectionPropertiesReceived(); +} + +// static +void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** user_data) +{ + LLUUID id; + + U32 request_flags; + LLUUID creator_id; + LLUUID owner_id; + LLUUID group_id; + LLUUID extra_id; + U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask; + LLSaleInfo sale_info; + LLCategory category; + + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_RequestFlags, request_flags ); + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, id ); + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id ); + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id ); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, base_mask ); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, owner_mask ); + msg->getU32Fast(_PREHASH_ObjectData,_PREHASH_GroupMask, group_mask ); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, everyone_mask ); + msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, next_owner_mask); + sale_info.unpackMessage(msg, _PREHASH_ObjectData); + category.unpackMessage(msg, _PREHASH_ObjectData); + + LLUUID last_owner_id; + msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, last_owner_id ); + + // unpack name & desc + std::string name; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, name); + + std::string desc; + msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, desc); + + // the reporter widget askes the server for info about picked objects + if (request_flags & COMPLAINT_REPORT_REQUEST ) + { + LLFloaterReporter *reporterp = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter"); + if (reporterp) + { + LLAvatarName av_name; + LLAvatarNameCache::get(owner_id, &av_name); + reporterp->setPickedObjectProperties(name, av_name.getUserName(), owner_id); + } + } + else if (request_flags & OBJECT_PAY_REQUEST) + { + // check if the owner of the paid object is muted + LLMuteList::getInstance()->autoRemove(owner_id, LLMuteList::AR_MONEY); + } + + // Now look through all of the hovered nodes + struct f : public LLSelectedNodeFunctor + { + LLUUID mID; + f(const LLUUID& id) : mID(id) {} + virtual bool apply(LLSelectNode* node) + { + return (node->getObject() && node->getObject()->mID == mID); + } + } func(id); + LLSelectNode* node = LLSelectMgr::getInstance()->mHoverObjects->getFirstNode(&func); + + if (node) + { + node->mValid = true; + node->mPermissions->init(LLUUID::null, owner_id, + last_owner_id, group_id); + node->mPermissions->initMasks(base_mask, owner_mask, everyone_mask, group_mask, next_owner_mask); + node->mSaleInfo = sale_info; + node->mCategory = category; + node->mName.assign(name); + node->mDescription.assign(desc); + } + + dialog_refresh_all(); +} + + +// static +void LLSelectMgr::processForceObjectSelect(LLMessageSystem* msg, void**) +{ + bool reset_list; + msg->getBOOL("Header", "ResetList", reset_list); + + if (reset_list) + { + LLSelectMgr::getInstance()->deselectAll(); + } + + LLUUID full_id; + S32 local_id; + LLViewerObject* object; + std::vector<LLViewerObject*> objects; + S32 i; + S32 block_count = msg->getNumberOfBlocks("Data"); + + for (i = 0; i < block_count; i++) + { + msg->getS32("Data", "LocalID", local_id, i); + + gObjectList.getUUIDFromLocal(full_id, + local_id, + msg->getSenderIP(), + msg->getSenderPort()); + object = gObjectList.findObject(full_id); + if (object) + { + objects.push_back(object); + } + } + + // Don't select, just highlight + LLSelectMgr::getInstance()->highlightObjectAndFamily(objects); +} + +extern F32 gGLModelView[16]; + +void LLSelectMgr::updateSilhouettes() +{ + S32 num_sils_genned = 0; + + LLVector3d cameraPos = gAgentCamera.getCameraPositionGlobal(); + F32 currentCameraZoom = gAgentCamera.getCurrentCameraBuildOffset(); + + if (!mSilhouetteImagep) + { + mSilhouetteImagep = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", FTT_LOCAL_FILE, true, LLGLTexture::BOOST_UI); + } + + mHighlightedObjects->cleanupNodes(); + + if((cameraPos - mLastCameraPos).magVecSquared() > SILHOUETTE_UPDATE_THRESHOLD_SQUARED * currentCameraZoom * currentCameraZoom) + { + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + object->setChanged(LLXform::SILHOUETTE); + return true; + } + } func; + getSelection()->applyToObjects(&func); + + mLastCameraPos = gAgentCamera.getCameraPositionGlobal(); + } + + std::vector<LLViewerObject*> changed_objects; + + updateSelectionSilhouette(mSelectedObjects, num_sils_genned, changed_objects); + if (mRectSelectedObjects.size() > 0) + { + //gGLSPipelineSelection.set(); + + //mSilhouetteImagep->bindTexture(); + //glAlphaFunc(GL_GREATER, sHighlightAlphaTest); + + std::set<LLViewerObject*> roots; + + // sync mHighlightedObjects with mRectSelectedObjects since the latter is rebuilt every frame and former + // persists from frame to frame to avoid regenerating object silhouettes + // mHighlightedObjects includes all siblings of rect selected objects + + bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); + + // generate list of roots from current object selection + for (std::set<LLPointer<LLViewerObject> >::iterator iter = mRectSelectedObjects.begin(); + iter != mRectSelectedObjects.end(); iter++) + { + LLViewerObject *objectp = *iter; + if (select_linked_set) + { + LLViewerObject *rootp = (LLViewerObject*)objectp->getRoot(); + roots.insert(rootp); + } + else + { + roots.insert(objectp); + } + } + + // remove highlight nodes not in roots list + std::vector<LLSelectNode*> remove_these_nodes; + std::vector<LLViewerObject*> remove_these_roots; + + for (LLObjectSelection::iterator iter = mHighlightedObjects->begin(); + iter != mHighlightedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + if (objectp->isRoot() || !select_linked_set) + { + if (roots.count(objectp) == 0) + { + remove_these_nodes.push_back(node); + } + else + { + remove_these_roots.push_back(objectp); + } + } + else + { + LLViewerObject* rootp = (LLViewerObject*)objectp->getRoot(); + + if (roots.count(rootp) == 0) + { + remove_these_nodes.push_back(node); + } + } + } + + // remove all highlight nodes no longer in rectangle selection + for (std::vector<LLSelectNode*>::iterator iter = remove_these_nodes.begin(); + iter != remove_these_nodes.end(); ++iter) + { + LLSelectNode* nodep = *iter; + mHighlightedObjects->removeNode(nodep); + } + + // remove all root objects already being highlighted + for (std::vector<LLViewerObject*>::iterator iter = remove_these_roots.begin(); + iter != remove_these_roots.end(); ++iter) + { + LLViewerObject* objectp = *iter; + roots.erase(objectp); + } + + // add all new objects in rectangle selection + for (std::set<LLViewerObject*>::iterator iter = roots.begin(); + iter != roots.end(); iter++) + { + LLViewerObject* objectp = *iter; + if (!canSelectObject(objectp)) + { + continue; + } + + LLSelectNode* rect_select_root_node = new LLSelectNode(objectp, true); + rect_select_root_node->selectAllTEs(true); + + if (!select_linked_set) + { + rect_select_root_node->mIndividualSelection = true; + } + else + { + LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child_objectp = *iter; + + if (!canSelectObject(child_objectp)) + { + continue; + } + + LLSelectNode* rect_select_node = new LLSelectNode(child_objectp, true); + rect_select_node->selectAllTEs(true); + mHighlightedObjects->addNodeAtEnd(rect_select_node); + } + } + + // Add the root last, to preserve order for link operations. + mHighlightedObjects->addNodeAtEnd(rect_select_root_node); + } + + num_sils_genned = 0; + + // render silhouettes for highlighted objects + //bool subtracting_from_selection = (gKeyboard->currentMask(true) == MASK_CONTROL); + for (S32 pass = 0; pass < 2; pass++) + { + for (LLObjectSelection::iterator iter = mHighlightedObjects->begin(); + iter != mHighlightedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + + // do roots first, then children so that root flags are cleared ASAP + bool roots_only = (pass == 0); + bool is_root = objectp->isRootEdit(); + if (roots_only != is_root) + { + continue; + } + + if (!node->mSilhouetteExists + || objectp->isChanged(LLXform::SILHOUETTE) + || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE))) + { + if (num_sils_genned++ < MAX_SILS_PER_FRAME) + { + generateSilhouette(node, LLViewerCamera::getInstance()->getOrigin()); + changed_objects.push_back(objectp); + } + else if (objectp->isAttachment() && objectp->getRootEdit()->mDrawable.notNull()) + { + //RN: hack for orthogonal projection of HUD attachments + LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent(); + if (attachment_pt && attachment_pt->getIsHUDAttachment()) + { + LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f); + generateSilhouette(node, camera_pos); + } + } + } + //LLColor4 highlight_color; + // + //if (subtracting_from_selection) + //{ + // node->renderOneSilhouette(LLColor4::red); + //} + //else if (!objectp->isSelected()) + //{ + // highlight_color = objectp->isRoot() ? sHighlightParentColor : sHighlightChildColor; + // node->renderOneSilhouette(highlight_color); + //} + } + } + //mSilhouetteImagep->unbindTexture(0, GL_TEXTURE_2D); + } + else + { + mHighlightedObjects->deleteAllNodes(); + } + + for (std::vector<LLViewerObject*>::iterator iter = changed_objects.begin(); + iter != changed_objects.end(); ++iter) + { + // clear flags after traversing node list (as child objects need to refer to parent flags, etc) + LLViewerObject* objectp = *iter; + objectp->clearChanged(LLXform::MOVED | LLXform::SILHOUETTE); + } +} + +void LLSelectMgr::updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects) +{ + if (object_handle->getNumNodes()) + { + //gGLSPipelineSelection.set(); + + //mSilhouetteImagep->bindTexture(); + //glAlphaFunc(GL_GREATER, sHighlightAlphaTest); + + for (S32 pass = 0; pass < 2; pass++) + { + for (LLObjectSelection::iterator iter = object_handle->begin(); + iter != object_handle->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + // do roots first, then children so that root flags are cleared ASAP + bool roots_only = (pass == 0); + bool is_root = (objectp->isRootEdit()); + if (roots_only != is_root || objectp->mDrawable.isNull()) + { + continue; + } + + if (!node->mSilhouetteExists + || objectp->isChanged(LLXform::SILHOUETTE) + || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE))) + { + if (num_sils_genned++ < MAX_SILS_PER_FRAME)// && objectp->mDrawable->isVisible()) + { + generateSilhouette(node, LLViewerCamera::getInstance()->getOrigin()); + changed_objects.push_back(objectp); + } + else if (objectp->isAttachment()) + { + //RN: hack for orthogonal projection of HUD attachments + LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent(); + if (attachment_pt && attachment_pt->getIsHUDAttachment()) + { + LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f); + generateSilhouette(node, camera_pos); + } + } + } + } + } + } +} +void LLSelectMgr::renderSilhouettes(bool for_hud) +{ + if (!mRenderSilhouettes || !mRenderHighlightSelections) + { + return; + } + + gGL.getTexUnit(0)->bind(mSilhouetteImagep); + LLGLSPipelineSelection gls_select; + LLGLEnable blend(GL_BLEND); + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); + + if (isAgentAvatarValid() && for_hud) + { + LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); + + F32 cur_zoom = gAgentCamera.mHUDCurZoom; + + // set up transform to encompass bounding box of HUD + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); + gGL.ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.pushUIMatrix(); + gGL.loadUIIdentity(); + gGL.loadIdentity(); + gGL.loadMatrix(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame + gGL.translatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f); + gGL.scalef(cur_zoom, cur_zoom, cur_zoom); + } + + bool wireframe_selection = (gFloaterTools && gFloaterTools->getVisible()) || LLSelectMgr::sRenderHiddenSelections; + F32 fogCfx = (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal() - gAgentCamera.getCameraPositionGlobal()).magVec() / (LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec() * 4), 0.0, 1.0); + + static LLColor4 sParentColor = LLColor4(sSilhouetteParentColor[VRED], sSilhouetteParentColor[VGREEN], sSilhouetteParentColor[VBLUE], LLSelectMgr::sHighlightAlpha); + static LLColor4 sChildColor = LLColor4(sSilhouetteChildColor[VRED], sSilhouetteChildColor[VGREEN], sSilhouetteChildColor[VBLUE], LLSelectMgr::sHighlightAlpha); + + auto renderMeshSelection_f = [fogCfx, wireframe_selection](LLSelectNode* node, LLViewerObject* objectp, LLColor4 hlColor) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (shader) + { + gDebugProgram.bind(); + } + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + + bool is_hud_object = objectp->isHUDAttachment(); + + if (!is_hud_object) + { + gGL.loadIdentity(); + gGL.multMatrix(gGLModelView); + } + + if (objectp->mDrawable->isActive()) + { + gGL.multMatrix((F32*)objectp->getRenderMatrix().mMatrix); + } + else if (!is_hud_object) + { + LLVector3 trans = objectp->getRegion()->getOriginAgent(); + gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); + } + + bool bRenderHidenSelection = node->isTransient() ? false : LLSelectMgr::sRenderHiddenSelections; + + + LLVOVolume* vobj = objectp->mDrawable->getVOVolume(); + if (vobj) + { + LLVertexBuffer::unbind(); + gGL.pushMatrix(); + gGL.multMatrix((F32*)vobj->getRelativeXform().mMatrix); + + if (objectp->mDrawable->isState(LLDrawable::RIGGED)) + { + vobj->updateRiggedVolume(true); + } + } + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); // avatars have TEs but no faces + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + objectp->mDrawable->getFace(te)->renderOneWireframe(hlColor, fogCfx, wireframe_selection, bRenderHidenSelection, nullptr != shader); + } + } + + gGL.popMatrix(); + gGL.popMatrix(); + + glLineWidth(1.f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + if (shader) + { + shader->bind(); + } + }; + + if (mSelectedObjects->getNumNodes()) + { + LLUUID inspect_item_id= LLUUID::null; + LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance<LLFloaterInspect>("inspect"); + if(inspect_instance && inspect_instance->getVisible()) + { + inspect_item_id = inspect_instance->getSelectedUUID(); + } + else + { + LLSidepanelTaskInfo *panel_task_info = LLSidepanelTaskInfo::getActivePanel(); + if (panel_task_info) + { + inspect_item_id = panel_task_info->getSelectedUUID(); + } + } + + LLUUID focus_item_id = LLViewerMediaFocus::getInstance()->getFocusedObjectID(); + for (S32 pass = 0; pass < 2; pass++) + { + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + + if (getTEMode() && !node->hasSelectedTE()) + continue; + + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + + if (objectp->mDrawable + && objectp->mDrawable->getVOVolume() + && objectp->mDrawable->getVOVolume()->isMesh()) + { + LLColor4 hlColor = objectp->isRootEdit() ? sParentColor : sChildColor; + if (objectp->getID() == inspect_item_id) + { + hlColor = sHighlightInspectColor; + } + else if (node->isTransient()) + { + hlColor = sContextSilhouetteColor; + } + renderMeshSelection_f(node, objectp, hlColor); + } + else + { + if (objectp->isHUDAttachment() != for_hud) + { + continue; + } + if (objectp->getID() == focus_item_id) + { + node->renderOneSilhouette(gFocusMgr.getFocusColor()); + } + else if (objectp->getID() == inspect_item_id) + { + node->renderOneSilhouette(sHighlightInspectColor); + } + else if (node->isTransient()) + { + bool oldHidden = LLSelectMgr::sRenderHiddenSelections; + LLSelectMgr::sRenderHiddenSelections = false; + node->renderOneSilhouette(sContextSilhouetteColor); + LLSelectMgr::sRenderHiddenSelections = oldHidden; + } + else if (objectp->isRootEdit()) + { + node->renderOneSilhouette(sSilhouetteParentColor); + } + else + { + node->renderOneSilhouette(sSilhouetteChildColor); + } + } + } //for all selected node's + } //for pass + } + + if (mHighlightedObjects->getNumNodes()) + { + // render silhouettes for highlighted objects + bool subtracting_from_selection = (gKeyboard->currentMask(true) == MASK_CONTROL); + for (S32 pass = 0; pass < 2; pass++) + { + for (LLObjectSelection::iterator iter = mHighlightedObjects->begin(); + iter != mHighlightedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + if (objectp->isHUDAttachment() != for_hud) + { + continue; + } + + LLColor4 highlight_color = objectp->isRoot() ? sHighlightParentColor : sHighlightChildColor; + if (objectp->mDrawable + && objectp->mDrawable->getVOVolume() + && objectp->mDrawable->getVOVolume()->isMesh()) + { + renderMeshSelection_f(node, objectp, subtracting_from_selection ? LLColor4::red : highlight_color); + } + else if (subtracting_from_selection) + { + node->renderOneSilhouette(LLColor4::red); + } + else if (!objectp->isSelected()) + { + node->renderOneSilhouette(highlight_color); + } + } + } + } + + if (isAgentAvatarValid() && for_hud) + { + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + gGL.popUIMatrix(); + stop_glerror(); + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +} + +void LLSelectMgr::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) +{ + LLViewerObject* objectp = nodep->getObject(); + + if (objectp && objectp->getPCode() == LL_PCODE_VOLUME) + { + ((LLVOVolume*)objectp)->generateSilhouette(nodep, view_point); + } +} + +// +// Utility classes +// +LLSelectNode::LLSelectNode(LLViewerObject* object, bool glow) +: mObject(object), + mIndividualSelection(false), + mTransient(false), + mValid(false), + mPermissions(new LLPermissions()), + mInventorySerial(0), + mSilhouetteExists(false), + mDuplicated(false), + mTESelectMask(0), + mLastTESelected(0), + mName(LLStringUtil::null), + mDescription(LLStringUtil::null), + mTouchName(LLStringUtil::null), + mSitName(LLStringUtil::null), + mCreationDate(0) +{ + saveColors(); + saveShinyColors(); +} + +LLSelectNode::LLSelectNode(const LLSelectNode& nodep) +{ + mTESelectMask = nodep.mTESelectMask; + mLastTESelected = nodep.mLastTESelected; + + mIndividualSelection = nodep.mIndividualSelection; + + mValid = nodep.mValid; + mTransient = nodep.mTransient; + mPermissions = new LLPermissions(*nodep.mPermissions); + mSaleInfo = nodep.mSaleInfo;; + mAggregatePerm = nodep.mAggregatePerm; + mAggregateTexturePerm = nodep.mAggregateTexturePerm; + mAggregateTexturePermOwner = nodep.mAggregateTexturePermOwner; + mName = nodep.mName; + mDescription = nodep.mDescription; + mCategory = nodep.mCategory; + mInventorySerial = 0; + mSavedPositionLocal = nodep.mSavedPositionLocal; + mSavedPositionGlobal = nodep.mSavedPositionGlobal; + mSavedScale = nodep.mSavedScale; + mSavedRotation = nodep.mSavedRotation; + mDuplicated = nodep.mDuplicated; + mDuplicatePos = nodep.mDuplicatePos; + mDuplicateRot = nodep.mDuplicateRot; + mItemID = nodep.mItemID; + mFolderID = nodep.mFolderID; + mFromTaskID = nodep.mFromTaskID; + mTouchName = nodep.mTouchName; + mSitName = nodep.mSitName; + mCreationDate = nodep.mCreationDate; + + mSilhouetteVertices = nodep.mSilhouetteVertices; + mSilhouetteNormals = nodep.mSilhouetteNormals; + mSilhouetteExists = nodep.mSilhouetteExists; + mObject = nodep.mObject; + + std::vector<LLColor4>::const_iterator color_iter; + mSavedColors.clear(); + for (color_iter = nodep.mSavedColors.begin(); color_iter != nodep.mSavedColors.end(); ++color_iter) + { + mSavedColors.push_back(*color_iter); + } + mSavedShinyColors.clear(); + for (color_iter = nodep.mSavedShinyColors.begin(); color_iter != nodep.mSavedShinyColors.end(); ++color_iter) + { + mSavedShinyColors.push_back(*color_iter); + } + + saveTextures(nodep.mSavedTextures); + saveGLTFMaterials(nodep.mSavedGLTFMaterialIds, nodep.mSavedGLTFOverrideMaterials); +} + +LLSelectNode::~LLSelectNode() +{ + LLSelectMgr *manager = LLSelectMgr::getInstance(); + if (manager->mAllowSelectAvatar + && (!mLastPositionLocal.isExactlyZero() + || mLastRotation != LLQuaternion())) + { + LLViewerObject* object = getObject(); //isDead() check + if (object && !object->getParent()) + { + LLVOAvatar* avatar = object->asAvatar(); + if (avatar) + { + // Avatar was moved and needs to stay that way + manager->mAvatarOverridesMap.emplace(avatar->getID(), LLSelectMgr::AvatarPositionOverride(mLastPositionLocal, mLastRotation, object)); + } + } + } + + + delete mPermissions; + mPermissions = NULL; +} + +void LLSelectNode::selectAllTEs(bool b) +{ + mTESelectMask = b ? TE_SELECT_MASK_ALL : 0x0; + mLastTESelected = 0; +} + +void LLSelectNode::selectTE(S32 te_index, bool selected) +{ + if (te_index < 0 || te_index >= SELECT_MAX_TES) + { + return; + } + S32 mask = 0x1 << te_index; + if(selected) + { + mTESelectMask |= mask; + } + else + { + mTESelectMask &= ~mask; + } + mLastTESelected = te_index; +} + +bool LLSelectNode::isTESelected(S32 te_index) const +{ + if (te_index < 0 || te_index >= mObject->getNumTEs()) + { + return false; + } + return (mTESelectMask & (0x1 << te_index)) != 0; +} + +S32 LLSelectNode::getLastSelectedTE() const +{ + if (!isTESelected(mLastTESelected)) + { + return -1; + } + return mLastTESelected; +} + +LLViewerObject* LLSelectNode::getObject() +{ + if (!mObject) + { + return NULL; + } + else if (mObject->isDead()) + { + mObject = NULL; + } + return mObject; +} + +void LLSelectNode::setObject(LLViewerObject* object) +{ + mObject = object; +} + +void LLSelectNode::saveColors() +{ + if (mObject.notNull()) + { + mSavedColors.clear(); + for (S32 i = 0; i < mObject->getNumTEs(); i++) + { + const LLTextureEntry* tep = mObject->getTE(i); + mSavedColors.push_back(tep->getColor()); + } + } +} + +void LLSelectNode::saveShinyColors() +{ + if (mObject.notNull()) + { + mSavedShinyColors.clear(); + for (S32 i = 0; i < mObject->getNumTEs(); i++) + { + const LLMaterialPtr mat = mObject->getTE(i)->getMaterialParams(); + if (!mat.isNull()) + { + mSavedShinyColors.push_back(mat->getSpecularLightColor()); + } + else + { + mSavedShinyColors.push_back(LLColor4::white); + } + } + } +} + +void LLSelectNode::saveTextures(const uuid_vec_t& textures) +{ + if (mObject.notNull()) + { + mSavedTextures.clear(); + + for (uuid_vec_t::const_iterator texture_it = textures.begin(); + texture_it != textures.end(); ++texture_it) + { + mSavedTextures.push_back(*texture_it); + } + } +} + +void LLSelectNode::saveGLTFMaterials(const uuid_vec_t& materials, const gltf_materials_vec_t& override_materials) +{ + if (mObject.notNull()) + { + mSavedGLTFMaterialIds.clear(); + mSavedGLTFOverrideMaterials.clear(); + + for (uuid_vec_t::const_iterator materials_it = materials.begin(); + materials_it != materials.end(); ++materials_it) + { + mSavedGLTFMaterialIds.push_back(*materials_it); + } + + for (gltf_materials_vec_t::const_iterator mat_it = override_materials.begin(); + mat_it != override_materials.end(); ++mat_it) + { + mSavedGLTFOverrideMaterials.push_back(*mat_it); + } + } +} + +void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query) +{ + mTextureScaleRatios.clear(); + + if (mObject.notNull()) + { + + LLVector3 scale = mObject->getScale(); + + for (U8 i = 0; i < mObject->getNumTEs(); i++) + { + F32 diffuse_s = 1.0f; + F32 diffuse_t = 1.0f; + + LLVector3 v; + const LLTextureEntry* tep = mObject->getTE(i); + if (!tep) + continue; + + U32 s_axis = VX; + U32 t_axis = VY; + LLPrimitive::getTESTAxes(i, &s_axis, &t_axis); + + tep->getScale(&diffuse_s,&diffuse_t); + + if (tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR) + { + v.mV[s_axis] = diffuse_s*scale.mV[s_axis]; + v.mV[t_axis] = diffuse_t*scale.mV[t_axis]; + mTextureScaleRatios.push_back(v); + } + else + { + v.mV[s_axis] = diffuse_s/scale.mV[s_axis]; + v.mV[t_axis] = diffuse_t/scale.mV[t_axis]; + mTextureScaleRatios.push_back(v); + } + } + } +} + + +// This implementation should be similar to LLTask::allowOperationOnTask +bool LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const +{ + // Extract ownership. + bool object_is_group_owned = false; + LLUUID object_owner_id; + mPermissions->getOwnership(object_owner_id, object_is_group_owned); + + // Operations on invalid or public objects is not allowed. + if (!mObject || (mObject->isDead()) || !mPermissions->isOwned()) + { + return false; + } + + // The transfer permissions can never be given through proxy. + if (PERM_TRANSFER == op) + { + // The owner of an agent-owned object can transfer to themselves. + if ( !object_is_group_owned + && (gAgent.getID() == object_owner_id) ) + { + return true; + } + else + { + // Otherwise check aggregate permissions. + return mObject->permTransfer(); + } + } + + if (PERM_MOVE == op + || PERM_MODIFY == op) + { + // only owners can move or modify their attachments + // no proxy allowed. + if (mObject->isAttachment() && object_owner_id != gAgent.getID()) + { + return false; + } + } + + // Calculate proxy_agent_id and group_id to use for permissions checks. + // proxy_agent_id may be set to the object owner through group powers. + // group_id can only be set to the object's group, if the agent is in that group. + LLUUID group_id = LLUUID::null; + LLUUID proxy_agent_id = gAgent.getID(); + + // Gods can always operate. + if (gAgent.isGodlike()) + { + return true; + } + + // Check if the agent is in the same group as the object. + LLUUID object_group_id = mPermissions->getGroup(); + if (object_group_id.notNull() && + gAgent.isInGroup(object_group_id)) + { + // Assume the object's group during this operation. + group_id = object_group_id; + } + + // Only allow proxy powers for PERM_COPY if the actual agent can + // receive the item (ie has PERM_TRANSFER permissions). + // NOTE: op == PERM_TRANSFER has already been handled, but if + // that ever changes we need to BLOCK proxy powers for PERM_TRANSFER. DK 03/28/06 + if (PERM_COPY != op || mPermissions->allowTransferTo(gAgent.getID())) + { + // Check if the agent can assume ownership through group proxy or agent-granted proxy. + if ( ( object_is_group_owned + && gAgent.hasPowerInGroup(object_owner_id, group_proxy_power)) + // Only allow proxy for move, modify, and copy. + || ( (PERM_MOVE == op || PERM_MODIFY == op || PERM_COPY == op) + && (!object_is_group_owned + && gAgent.isGrantedProxy(*mPermissions)))) + { + // This agent is able to assume the ownership role for this operation. + proxy_agent_id = object_owner_id; + } + } + + // We now have max ownership information. + if (PERM_OWNER == op) + { + // This this was just a check for ownership, we can now return the answer. + return proxy_agent_id == object_owner_id; + } + + // check permissions to see if the agent can operate + return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id)); +} + +//----------------------------------------------------------------------------- +// renderOneSilhouette() +//----------------------------------------------------------------------------- +void LLSelectNode::renderOneSilhouette(const LLColor4 &color) +{ + LLViewerObject* objectp = getObject(); + if (!objectp) + { + return; + } + + LLDrawable* drawable = objectp->mDrawable; + if(!drawable) + { + return; + } + + LLVOVolume* vobj = drawable->getVOVolume(); + if (vobj && vobj->isMesh()) + { + //This check (if(...)) with assert here just for ensure that this situation will not happens, and can be removed later. For example on the next release. + llassert(!"renderOneWireframe() was removed SL-10194"); + return; + } + + if (!mSilhouetteExists) + { + return; + } + + bool is_hud_object = objectp->isHUDAttachment(); + + if (mSilhouetteVertices.size() == 0 || mSilhouetteNormals.size() != mSilhouetteVertices.size()) + { + return; + } + + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (shader) + { //use UI program for selection highlights (texture color modulated by vertex color) + gUIProgram.bind(); + } + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.pushUIMatrix(); + gGL.loadUIIdentity(); + + if (!is_hud_object) + { + gGL.loadIdentity(); + gGL.multMatrix(gGLModelView); + } + + + if (drawable->isActive()) + { + gGL.multMatrix((F32*) objectp->getRenderMatrix().mMatrix); + } + + LLVolume *volume = objectp->getVolume(); + if (volume) + { + F32 silhouette_thickness; + if (isAgentAvatarValid() && is_hud_object) + { + silhouette_thickness = LLSelectMgr::sHighlightThickness / gAgentCamera.mHUDCurZoom; + } + else + { + LLVector3 view_vector = LLViewerCamera::getInstance()->getOrigin() - objectp->getRenderPosition(); + silhouette_thickness = view_vector.magVec() * LLSelectMgr::sHighlightThickness * (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()); + } + F32 animationTime = (F32)LLFrameTimer::getElapsedSeconds(); + + F32 u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f); + F32 v_coord = 1.f - fmod(animationTime * LLSelectMgr::sHighlightVAnim, 1.f); + F32 u_divisor = 1.f / ((F32)(mSilhouetteVertices.size() - 1)); + + if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible()) + { + gGL.flush(); + gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE); + + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL); + gGL.flush(); + gGL.begin(LLRender::LINES); + { + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); + + for(S32 i = 0; i < mSilhouetteVertices.size(); i += 2) + { + u_coord += u_divisor * LLSelectMgr::sHighlightUScale; + gGL.texCoord2f( u_coord, v_coord ); + gGL.vertex3fv( mSilhouetteVertices[i].mV); + u_coord += u_divisor * LLSelectMgr::sHighlightUScale; + gGL.texCoord2f( u_coord, v_coord ); + gGL.vertex3fv(mSilhouetteVertices[i+1].mV); + } + } + gGL.end(); + u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f); + } + + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.begin(LLRender::TRIANGLES); + { + for(S32 i = 0; i < mSilhouetteVertices.size(); i+=2) + { + if (!mSilhouetteNormals[i].isFinite() || + !mSilhouetteNormals[i+1].isFinite()) + { //skip skewed segments + continue; + } + + LLVector3 v[4]; + LLVector2 tc[4]; + v[0] = mSilhouetteVertices[i] + (mSilhouetteNormals[i] * silhouette_thickness); + tc[0].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale); + + v[1] = mSilhouetteVertices[i]; + tc[1].set(u_coord, v_coord); + + u_coord += u_divisor * LLSelectMgr::sHighlightUScale; + + v[2] = mSilhouetteVertices[i+1] + (mSilhouetteNormals[i+1] * silhouette_thickness); + tc[2].set(u_coord, v_coord + LLSelectMgr::sHighlightVScale); + + v[3] = mSilhouetteVertices[i+1]; + tc[3].set(u_coord,v_coord); + + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha); + gGL.texCoord2fv(tc[0].mV); + gGL.vertex3fv( v[0].mV ); + + gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha); + gGL.texCoord2fv( tc[1].mV ); + gGL.vertex3fv( v[1].mV ); + + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha); + gGL.texCoord2fv( tc[2].mV ); + gGL.vertex3fv( v[2].mV ); + + gGL.vertex3fv( v[2].mV ); + + gGL.color4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha); + gGL.texCoord2fv( tc[1].mV ); + gGL.vertex3fv( v[1].mV ); + + gGL.texCoord2fv( tc[3].mV ); + gGL.vertex3fv( v[3].mV ); + } + } + gGL.end(); + gGL.flush(); + } + gGL.popMatrix(); + gGL.popUIMatrix(); + + if (shader) + { + shader->bind(); + } +} + +// +// Utility Functions +// + +// *DEPRECATED: See header comment. +void dialog_refresh_all() +{ + // This is the easiest place to fire the update signal, as it will + // make cleaning up the functions below easier. Also, sometimes entities + // outside the selection manager change properties of selected objects + // and call into this function. Yuck. + LLSelectMgr::getInstance()->mUpdateSignal(); + + // *TODO: Eliminate all calls into outside classes below, make those + // objects register with the update signal. + + gFloaterTools->dirty(); + + gMenuObject->needsArrange(); + + if( gMenuAttachmentSelf->getVisible() ) + { + gMenuAttachmentSelf->arrange(); + } + if( gMenuAttachmentOther->getVisible() ) + { + gMenuAttachmentOther->arrange(); + } + + LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance<LLFloaterInspect>("inspect"); + if(inspect_instance) + { + inspect_instance->dirty(); + } + + LLSidepanelTaskInfo *panel_task_info = LLSidepanelTaskInfo::getActivePanel(); + if (panel_task_info) + { + panel_task_info->dirty(); + } +} + +S32 get_family_count(LLViewerObject *parent) +{ + if (!parent) + { + LL_WARNS() << "Trying to get_family_count on null parent!" << LL_ENDL; + } + S32 count = 1; // for this object + LLViewerObject::const_child_list_t& child_list = parent->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); iter++) + { + LLViewerObject* child = *iter; + + if (!child) + { + LL_WARNS() << "Family object has NULL child! Show Doug." << LL_ENDL; + } + else if (child->isDead()) + { + LL_WARNS() << "Family object has dead child object. Show Doug." << LL_ENDL; + } + else + { + if (LLSelectMgr::getInstance()->canSelectObject(child)) + { + count += get_family_count( child ); + } + } + } + return count; +} + +//----------------------------------------------------------------------------- +// updateSelectionCenter +// +// FIXME this is a grab bag of functionality only some of which has to do +// with the selection center +// ----------------------------------------------------------------------------- +void LLSelectMgr::updateSelectionCenter() +{ + const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection + // center (tractor beam) + + // override any avatar updates received + // Works only if avatar was repositioned + // and edit floater is visible + overrideAvatarUpdates(); + //override any object updates received + //for selected objects + overrideObjectUpdates(); + + LLViewerObject* object = mSelectedObjects->getFirstObject(); + if (!object) + { + // nothing selected, probably grabbing + // Ignore by setting to avatar origin. + mSelectionCenterGlobal.clearVec(); + mShowSelection = false; + mSelectionBBox = LLBBox(); + resetAgentHUDZoom(); + } + else + { + mSelectedObjects->mSelectType = getSelectTypeForObject(object); + + if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) + { + // reset hud ZOOM + resetAgentHUDZoom(); + } + + mShowSelection = false; + LLBBox bbox; + + // have stuff selected + LLVector3d select_center; + // keep a list of jointed objects for showing the joint HUDEffects + + // Initialize the bounding box to the root prim, so the BBox orientation + // matches the root prim's (affecting the orientation of the manipulators). + bbox.addBBoxAgent( (mSelectedObjects->getFirstRootObject(true))->getBoundingBoxAgent() ); + + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (!object) + continue; + + LLViewerObject *root = object->getRootEdit(); + if (mSelectedObjects->mSelectType == SELECT_TYPE_WORLD && // not an attachment + !root->isChild(gAgentAvatarp) && // not the object you're sitting on + !object->isAvatar()) // not another avatar + { + mShowSelection = true; + } + + bbox.addBBoxAgent( object->getBoundingBoxAgent() ); + } + + LLVector3 bbox_center_agent = bbox.getCenterAgent(); + mSelectionCenterGlobal = gAgent.getPosGlobalFromAgent(bbox_center_agent); + mSelectionBBox = bbox; + + } + + if ( !(gAgentID == LLUUID::null)) + { + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + if (mShowSelection) + { + LLVector3d select_center_global; + + if( tool->isEditing() ) + { + select_center_global = tool->getEditingPointGlobal(); + } + else + { + select_center_global = mSelectionCenterGlobal; + } + + // Send selection center if moved beyond threshold (used to animate tractor beam) + LLVector3d diff; + diff = select_center_global - mLastSentSelectionCenterGlobal; + + if ( diff.magVecSquared() > MOVE_SELECTION_THRESHOLD*MOVE_SELECTION_THRESHOLD ) + { + // Transmit updated selection center + mLastSentSelectionCenterGlobal = select_center_global; + } + } + } + + // give up edit menu if no objects selected + if (gEditMenuHandler == this && mSelectedObjects->getObjectCount() == 0) + { + gEditMenuHandler = NULL; + } + + pauseAssociatedAvatars(); +} + +//----------------------------------------------------------------------------- +// pauseAssociatedAvatars +// +// If the selection includes an attachment or an animated object, the +// associated avatars should pause their animations until they are no +// longer selected. +//----------------------------------------------------------------------------- +void LLSelectMgr::pauseAssociatedAvatars() +{ + mPauseRequests.clear(); + + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (!object) + continue; + + mSelectedObjects->mSelectType = getSelectTypeForObject(object); + + LLVOAvatar* parent_av = NULL; + if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT) + { + // Selection can be obsolete, confirm that this is an attachment + // and find parent avatar + parent_av = object->getAvatarAncestor(); + } + + // Can be both an attachment and animated object + if (parent_av) + { + // It's an attachment. Pause the avatar it's attached to. + mPauseRequests.push_back(parent_av->requestPause()); + } + + if (object->isAnimatedObject() && object->getControlAvatar()) + { + // It's an animated object. Pause the control avatar. + mPauseRequests.push_back(object->getControlAvatar()->requestPause()); + } + } +} + +void LLSelectMgr::updatePointAt() +{ + if (mShowSelection) + { + if (mSelectedObjects->getObjectCount()) + { + LLVector3 select_offset; + const LLPickInfo& pick = gViewerWindow->getLastPick(); + LLViewerObject *click_object = pick.getObject(); + if (click_object && click_object->isSelected()) + { + // clicked on another object in our selection group, use that as target + select_offset.setVec(pick.mObjectOffset); + select_offset.rotVec(~click_object->getRenderRotation()); + + gAgentCamera.setPointAt(POINTAT_TARGET_SELECT, click_object, select_offset); + gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, click_object, select_offset); + } + else + { + // didn't click on an object this time, revert to pointing at center of first object + gAgentCamera.setPointAt(POINTAT_TARGET_SELECT, mSelectedObjects->getFirstObject()); + gAgentCamera.setLookAt(LOOKAT_TARGET_SELECT, mSelectedObjects->getFirstObject()); + } + } + else + { + gAgentCamera.setPointAt(POINTAT_TARGET_CLEAR); + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + } + } + else + { + gAgentCamera.setPointAt(POINTAT_TARGET_CLEAR); + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + } +} + +//----------------------------------------------------------------------------- +// getBBoxOfSelection() +//----------------------------------------------------------------------------- +LLBBox LLSelectMgr::getBBoxOfSelection() const +{ + return mSelectionBBox; +} + + +//----------------------------------------------------------------------------- +// canUndo() +//----------------------------------------------------------------------------- +bool LLSelectMgr::canUndo() const +{ + // Can edit or can move + return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstUndoEnabledObject() != NULL; // HACK: casting away constness - MG; +} + +//----------------------------------------------------------------------------- +// undo() +//----------------------------------------------------------------------------- +void LLSelectMgr::undo() +{ + bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); + LLUUID group_id(gAgent.getGroupID()); + sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST); +} + +//----------------------------------------------------------------------------- +// canRedo() +//----------------------------------------------------------------------------- +bool LLSelectMgr::canRedo() const +{ + return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstEditableObject() != NULL; // HACK: casting away constness - MG +} + +//----------------------------------------------------------------------------- +// redo() +//----------------------------------------------------------------------------- +void LLSelectMgr::redo() +{ + bool select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); + LLUUID group_id(gAgent.getGroupID()); + sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST); +} + +//----------------------------------------------------------------------------- +// canDoDelete() +//----------------------------------------------------------------------------- +bool LLSelectMgr::canDoDelete() const +{ + bool can_delete = false; + // This function is "logically const" - it does not change state in + // a way visible outside the selection manager. + LLSelectMgr* self = const_cast<LLSelectMgr*>(this); + LLViewerObject* obj = self->mSelectedObjects->getFirstDeleteableObject(); + // Note: Can only delete root objects (see getFirstDeleteableObject() for more info) + if (obj!= NULL) + { + // all the faces needs to be selected + if(self->mSelectedObjects->contains(obj,SELECT_ALL_TES )) + { + can_delete = true; + } + } + + return can_delete; +} + +//----------------------------------------------------------------------------- +// doDelete() +//----------------------------------------------------------------------------- +void LLSelectMgr::doDelete() +{ + selectDelete(); +} + +//----------------------------------------------------------------------------- +// canDeselect() +//----------------------------------------------------------------------------- +bool LLSelectMgr::canDeselect() const +{ + return !mSelectedObjects->isEmpty(); +} + +//----------------------------------------------------------------------------- +// deselect() +//----------------------------------------------------------------------------- +void LLSelectMgr::deselect() +{ + deselectAll(); +} +//----------------------------------------------------------------------------- +// canDuplicate() +//----------------------------------------------------------------------------- +bool LLSelectMgr::canDuplicate() const +{ + return const_cast<LLSelectMgr*>(this)->mSelectedObjects->getFirstCopyableObject() != NULL; // HACK: casting away constness - MG +} +//----------------------------------------------------------------------------- +// duplicate() +//----------------------------------------------------------------------------- +void LLSelectMgr::duplicate() +{ + LLVector3 offset(0.5f, 0.5f, 0.f); + selectDuplicate(offset, true); +} + +ESelectType LLSelectMgr::getSelectTypeForObject(LLViewerObject* object) +{ + if (!object) + { + return SELECT_TYPE_WORLD; + } + if (object->isHUDAttachment()) + { + return SELECT_TYPE_HUD; + } + else if (object->isAttachment()) + { + return SELECT_TYPE_ATTACHMENT; + } + else + { + return SELECT_TYPE_WORLD; + } +} + +void LLSelectMgr::validateSelection() +{ + struct f : public LLSelectedObjectFunctor + { + virtual bool apply(LLViewerObject* object) + { + if (!LLSelectMgr::getInstance()->canSelectObject(object)) + { + LLSelectMgr::getInstance()->deselectObjectOnly(object); + } + return true; + } + } func; + getSelection()->applyToObjects(&func); +} + +bool LLSelectMgr::canSelectObject(LLViewerObject* object, bool ignore_select_owned) +{ + // Never select dead objects + if (!object || object->isDead()) + { + return false; + } + + if (mForceSelection) + { + return true; + } + + if(!ignore_select_owned) + { + if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) || + (gSavedSettings.getBOOL("SelectMovableOnly") && (!object->permMove() || object->isPermanentEnforced()))) + { + // only select my own objects + return false; + } + } + + // Can't select orphans + if (object->isOrphaned()) return false; + + // Can't select avatars + if (object->isAvatar()) return false; + + // Can't select land + if (object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) return false; + + ESelectType selection_type = getSelectTypeForObject(object); + if (mSelectedObjects->getObjectCount() > 0 && mSelectedObjects->mSelectType != selection_type) return false; + + return true; +} + +bool LLSelectMgr::setForceSelection(bool force) +{ + std::swap(mForceSelection,force); + return force; +} + +void LLSelectMgr::resetAgentHUDZoom() +{ + if (gAgentCamera.mHUDTargetZoom != 1) + { + gAgentCamera.mHUDTargetZoom = 1.f; + gAgentCamera.mHUDCurZoom = 1.f; + } +} + +void LLSelectMgr::getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const +{ + target_zoom = gAgentCamera.mHUDTargetZoom; + current_zoom = gAgentCamera.mHUDCurZoom; +} + +void LLSelectMgr::setAgentHUDZoom(F32 target_zoom, F32 current_zoom) +{ + gAgentCamera.mHUDTargetZoom = target_zoom; + gAgentCamera.mHUDCurZoom = current_zoom; +} + +///////////////////////////////////////////////////////////////////////////// +// Object selection iterator helpers +///////////////////////////////////////////////////////////////////////////// +bool LLObjectSelection::is_root::operator()(LLSelectNode *node) +{ + LLViewerObject* object = node->getObject(); + return (object != NULL) && !node->mIndividualSelection && (object->isRootEdit()); +} + +bool LLObjectSelection::is_valid_root::operator()(LLSelectNode *node) +{ + LLViewerObject* object = node->getObject(); + return (object != NULL) && node->mValid && !node->mIndividualSelection && (object->isRootEdit()); +} + +bool LLObjectSelection::is_root_object::operator()(LLSelectNode *node) +{ + LLViewerObject* object = node->getObject(); + return (object != NULL) && (object->isRootEdit()); +} + +LLObjectSelection::LLObjectSelection() : + LLRefCount(), + mSelectType(SELECT_TYPE_WORLD) +{ +} + +LLObjectSelection::~LLObjectSelection() +{ + deleteAllNodes(); +} + +void LLObjectSelection::cleanupNodes() +{ + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ) + { + list_t::iterator curiter = iter++; + LLSelectNode* node = *curiter; + if (node->getObject() == NULL || node->getObject()->isDead()) + { + mList.erase(curiter); + delete node; + } + } +} + +void LLObjectSelection::updateEffects() +{ +} + +S32 LLObjectSelection::getNumNodes() +{ + return mList.size(); +} + +void LLObjectSelection::addNode(LLSelectNode *nodep) +{ + llassert_always(nodep->getObject() && !nodep->getObject()->isDead()); + mList.push_front(nodep); + mSelectNodeMap[nodep->getObject()] = nodep; +} + +void LLObjectSelection::addNodeAtEnd(LLSelectNode *nodep) +{ + llassert_always(nodep->getObject() && !nodep->getObject()->isDead()); + mList.push_back(nodep); + mSelectNodeMap[nodep->getObject()] = nodep; +} + +void LLObjectSelection::moveNodeToFront(LLSelectNode *nodep) +{ + mList.remove(nodep); + mList.push_front(nodep); +} + +void LLObjectSelection::removeNode(LLSelectNode *nodep) +{ + mSelectNodeMap.erase(nodep->getObject()); + if (nodep->getObject() == mPrimaryObject) + { + mPrimaryObject = NULL; + } + nodep->setObject(NULL); // Will get erased in cleanupNodes() + mList.remove(nodep); +} + +void LLObjectSelection::deleteAllNodes() +{ + std::for_each(mList.begin(), mList.end(), DeletePointer()); + mList.clear(); + mSelectNodeMap.clear(); + mPrimaryObject = NULL; +} + +LLSelectNode* LLObjectSelection::findNode(LLViewerObject* objectp) +{ + std::map<LLPointer<LLViewerObject>, LLSelectNode*>::iterator found_it = mSelectNodeMap.find(objectp); + if (found_it != mSelectNodeMap.end()) + { + return found_it->second; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// isEmpty() +//----------------------------------------------------------------------------- +bool LLObjectSelection::isEmpty() const +{ + return (mList.size() == 0); +} + + +//----------------------------------------------------------------------------- +// getObjectCount() - returns number of non null objects +//----------------------------------------------------------------------------- +S32 LLObjectSelection::getObjectCount() +{ + cleanupNodes(); + S32 count = mList.size(); + + return count; +} + +F32 LLObjectSelection::getSelectedObjectCost() +{ + cleanupNodes(); + F32 cost = 0.f; + + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + cost += object->getObjectCost(); + } + } + + return cost; +} + +F32 LLObjectSelection::getSelectedLinksetCost() +{ + cleanupNodes(); + F32 cost = 0.f; + + std::set<LLViewerObject*> me_roots; + + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object && !object->isAttachment()) + { + LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot()); + if (root) + { + if (me_roots.find(root) == me_roots.end()) + { + me_roots.insert(root); + cost += root->getLinksetCost(); + } + } + } + } + + return cost; +} + +F32 LLObjectSelection::getSelectedPhysicsCost() +{ + cleanupNodes(); + F32 cost = 0.f; + + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + cost += object->getPhysicsCost(); + } + } + + return cost; +} + +F32 LLObjectSelection::getSelectedLinksetPhysicsCost() +{ + cleanupNodes(); + F32 cost = 0.f; + + std::set<LLViewerObject*> me_roots; + + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + LLViewerObject* root = static_cast<LLViewerObject*>(object->getRoot()); + if (root) + { + if (me_roots.find(root) == me_roots.end()) + { + me_roots.insert(root); + cost += root->getLinksetPhysicsCost(); + } + } + } + } + + return cost; +} + +F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* visible_bytes) +{ + F32 cost = 0.f; + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + cost += object->getStreamingCost(); + + S32 bytes = 0; + S32 visible = 0; + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } + if (total_bytes) + { + *total_bytes += bytes; + } + + if (visible_bytes) + { + *visible_bytes += visible; + } + } + } + + return cost; +} + +U32 LLObjectSelection::getSelectedObjectTriangleCount(S32* vcount) +{ + U32 count = 0; + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + + if (object) + { + S32 vt = 0; + count += object->getTriangleCount(&vt); + *vcount += vt; + } + } + + return count; +} + +S32 LLObjectSelection::getSelectedObjectRenderCost() +{ + S32 cost = 0; + LLVOVolume::texture_cost_t textures; + typedef std::set<LLUUID> uuid_list_t; + uuid_list_t computed_objects; + + typedef std::list<LLPointer<LLViewerObject> > child_list_t; + typedef const child_list_t const_child_list_t; + + // add render cost of complete linksets first, to get accurate texture counts + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + + LLVOVolume* object = (LLVOVolume*)node->getObject(); + + if (object && object->isRootEdit()) + { + cost += object->getRenderCost(textures); + computed_objects.insert(object->getID()); + + const_child_list_t children = object->getChildren(); + for (const_child_list_t::const_iterator child_iter = children.begin(); + child_iter != children.end(); + ++child_iter) + { + LLViewerObject* child_obj = *child_iter; + LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); + if (child) + { + cost += child->getRenderCost(textures); + computed_objects.insert(child->getID()); + } + } + + for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) + { + // add the cost of each individual texture in the linkset + cost += LLVOVolume::getTextureCost(*iter); + } + + textures.clear(); + } + } + + // add any partial linkset objects, texture cost may be slightly misleading + for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter) + { + LLSelectNode* node = *iter; + LLVOVolume* object = (LLVOVolume*)node->getObject(); + + if (object && computed_objects.find(object->getID()) == computed_objects.end() ) + { + cost += object->getRenderCost(textures); + computed_objects.insert(object->getID()); + } + + for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) + { + // add the cost of each individual texture in the linkset + cost += LLVOVolume::getTextureCost(*iter); + } + + textures.clear(); + } + + return cost; +} + +//----------------------------------------------------------------------------- +// getTECount() +//----------------------------------------------------------------------------- +S32 LLObjectSelection::getTECount() +{ + S32 count = 0; + for (LLObjectSelection::iterator iter = begin(); iter != end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (!object) + continue; + S32 num_tes = object->getNumTEs(); + for (S32 te = 0; te < num_tes; te++) + { + if (node->isTESelected(te)) + { + ++count; + } + } + } + return count; +} + +//----------------------------------------------------------------------------- +// getRootObjectCount() +//----------------------------------------------------------------------------- +S32 LLObjectSelection::getRootObjectCount() +{ + S32 count = 0; + for (LLObjectSelection::root_iterator iter = root_begin(); iter != root_end(); iter++) + { + ++count; + } + return count; +} + +bool LLObjectSelection::applyToObjects(LLSelectedObjectFunctor* func) +{ + bool result = true; + for (iterator iter = begin(); iter != end(); ) + { + iterator nextiter = iter++; + LLViewerObject* object = (*nextiter)->getObject(); + if (!object) + continue; + bool r = func->apply(object); + result = result && r; + } + return result; +} + +bool LLObjectSelection::checkAnimatedObjectEstTris() +{ + F32 est_tris = 0; + F32 max_tris = 0; + S32 anim_count = 0; + for (root_iterator iter = root_begin(); iter != root_end(); ++iter) + { + LLViewerObject* object = (*iter)->getObject(); + if (!object) + continue; + if (object->isAnimatedObject()) + { + anim_count++; + } + est_tris += object->recursiveGetEstTrianglesMax(); + max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); + } + return anim_count==0 || est_tris <= max_tris; +} + +bool LLObjectSelection::checkAnimatedObjectLinkable() +{ + return checkAnimatedObjectEstTris(); +} + +bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly) +{ + bool result = !firstonly; + for (root_iterator iter = root_begin(); iter != root_end(); ) + { + root_iterator nextiter = iter++; + LLViewerObject* object = (*nextiter)->getObject(); + if (!object) + continue; + bool r = func->apply(object); + if (firstonly && r) + return true; + else + result = result && r; + } + return result; +} + +bool LLObjectSelection::applyToTEs(LLSelectedTEFunctor* func, bool firstonly) +{ + bool result = !firstonly; + for (iterator iter = begin(); iter != end(); ) + { + iterator nextiter = iter++; + LLSelectNode* node = *nextiter; + LLViewerObject* object = (*nextiter)->getObject(); + if (!object) + continue; + S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); // avatars have TEs but no faces + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + bool r = func->apply(object, te); + if (firstonly && r) + return true; + else + result = result && r; + } + } + } + return result; +} + +bool LLObjectSelection::applyToNodes(LLSelectedNodeFunctor *func, bool firstonly) +{ + bool result = !firstonly; + for (iterator iter = begin(); iter != end(); ) + { + iterator nextiter = iter++; + LLSelectNode* node = *nextiter; + bool r = func->apply(node); + if (firstonly && r) + return true; + else + result = result && r; + } + return result; +} + +bool LLObjectSelection::applyToRootNodes(LLSelectedNodeFunctor *func, bool firstonly) +{ + bool result = !firstonly; + for (root_iterator iter = root_begin(); iter != root_end(); ) + { + root_iterator nextiter = iter++; + LLSelectNode* node = *nextiter; + bool r = func->apply(node); + if (firstonly && r) + return true; + else + result = result && r; + } + return result; +} + +bool LLObjectSelection::isMultipleTESelected() +{ + bool te_selected = false; + // ...all faces + for (LLObjectSelection::iterator iter = begin(); + iter != end(); iter++) + { + LLSelectNode* nodep = *iter; + for (S32 i = 0; i < SELECT_MAX_TES; i++) + { + if(nodep->isTESelected(i)) + { + if(te_selected) + { + return true; + } + te_selected = true; + } + } + } + return false; +} + +//----------------------------------------------------------------------------- +// contains() +//----------------------------------------------------------------------------- +bool LLObjectSelection::contains(LLViewerObject* object) +{ + return findNode(object) != NULL; +} + + +//----------------------------------------------------------------------------- +// contains() +//----------------------------------------------------------------------------- +bool LLObjectSelection::contains(LLViewerObject* object, S32 te) +{ + if (te == SELECT_ALL_TES) + { + // ...all faces + for (LLObjectSelection::iterator iter = begin(); + iter != end(); iter++) + { + LLSelectNode* nodep = *iter; + if (nodep->getObject() == object) + { + // Optimization + if (nodep->getTESelectMask() == TE_SELECT_MASK_ALL) + { + return true; + } + + bool all_selected = true; + for (S32 i = 0; i < object->getNumTEs(); i++) + { + all_selected = all_selected && nodep->isTESelected(i); + } + return all_selected; + } + } + return false; + } + else + { + // ...one face + for (LLObjectSelection::iterator iter = begin(); iter != end(); iter++) + { + LLSelectNode* nodep = *iter; + if (nodep->getObject() == object && nodep->isTESelected(te)) + { + return true; + } + } + return false; + } +} + +// returns true is any node is currenly worn as an attachment +bool LLObjectSelection::isAttachment() +{ + return (mSelectType == SELECT_TYPE_ATTACHMENT || mSelectType == SELECT_TYPE_HUD); +} + +//----------------------------------------------------------------------------- +// getSelectedParentObject() +//----------------------------------------------------------------------------- +LLViewerObject* getSelectedParentObject(LLViewerObject *object) +{ + LLViewerObject *parent; + while (object && (parent = (LLViewerObject*)object->getParent())) + { + if (parent->isSelected()) + { + object = parent; + } + else + { + break; + } + } + return object; +} + +//----------------------------------------------------------------------------- +// getFirstNode +//----------------------------------------------------------------------------- +LLSelectNode* LLObjectSelection::getFirstNode(LLSelectedNodeFunctor* func) +{ + for (iterator iter = begin(); iter != end(); ++iter) + { + LLSelectNode* node = *iter; + if (func == NULL || func->apply(node)) + { + return node; + } + } + return NULL; +} + +LLSelectNode* LLObjectSelection::getFirstRootNode(LLSelectedNodeFunctor* func, bool non_root_ok) +{ + for (root_iterator iter = root_begin(); iter != root_end(); ++iter) + { + LLSelectNode* node = *iter; + if (func == NULL || func->apply(node)) + { + return node; + } + } + if (non_root_ok) + { + // Get non root + return getFirstNode(func); + } + return NULL; +} + + +//----------------------------------------------------------------------------- +// getFirstSelectedObject +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstSelectedObject(LLSelectedNodeFunctor* func, bool get_parent) +{ + LLSelectNode* res = getFirstNode(func); + if (res && get_parent) + { + return getSelectedParentObject(res->getObject()); + } + else if (res) + { + return res->getObject(); + } + return NULL; +} + +//----------------------------------------------------------------------------- +// getFirstObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstObject() +{ + LLSelectNode* res = getFirstNode(NULL); + return res ? res->getObject() : NULL; +} + +//----------------------------------------------------------------------------- +// getFirstRootObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstRootObject(bool non_root_ok) +{ + LLSelectNode* res = getFirstRootNode(NULL, non_root_ok); + return res ? res->getObject() : NULL; +} + +//----------------------------------------------------------------------------- +// getFirstMoveableNode() +//----------------------------------------------------------------------------- +LLSelectNode* LLObjectSelection::getFirstMoveableNode(bool get_root_first) +{ + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + return obj && obj->permMove() && !obj->isPermanentEnforced(); + } + } func; + LLSelectNode* res = get_root_first ? getFirstRootNode(&func, true) : getFirstNode(&func); + return res; +} + +//----------------------------------------------------------------------------- +// getFirstCopyableObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstCopyableObject(bool get_parent) +{ + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + return obj && obj->permCopy() && !obj->isAttachment(); + } + } func; + return getFirstSelectedObject(&func, get_parent); +} + +//----------------------------------------------------------------------------- +// getFirstDeleteableObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstDeleteableObject() +{ + //RN: don't currently support deletion of child objects, as that requires separating them first + // then derezzing to trash + + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + // you can delete an object if you are the owner + // or you have permission to modify it. + if( obj && !obj->isPermanentEnforced() && + ( (obj->permModify()) || + (obj->permYouOwner()) || + (!obj->permAnyOwner()) )) // public + { + if( !obj->isAttachment() ) + { + return true; + } + } + return false; + } + } func; + LLSelectNode* node = getFirstNode(&func); + return node ? node->getObject() : NULL; +} + +//----------------------------------------------------------------------------- +// getFirstEditableObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstEditableObject(bool get_parent) +{ + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + return obj && obj->permModify(); + } + } func; + return getFirstSelectedObject(&func, get_parent); +} + +//----------------------------------------------------------------------------- +// getFirstMoveableObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstMoveableObject(bool get_parent) +{ + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + return obj && obj->permMove() && !obj->isPermanentEnforced(); + } + } func; + return getFirstSelectedObject(&func, get_parent); +} + +//----------------------------------------------------------------------------- +// getFirstUndoEnabledObject() +//----------------------------------------------------------------------------- +LLViewerObject* LLObjectSelection::getFirstUndoEnabledObject(bool get_parent) +{ + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) + { + LLViewerObject* obj = node->getObject(); + return obj && (obj->permModify() || (obj->permMove() && !obj->isPermanentEnforced())); + } + } func; + return getFirstSelectedObject(&func, get_parent); +} + +//----------------------------------------------------------------------------- +// Position + Rotation update methods called from LLViewerJoystick +//----------------------------------------------------------------------------- +bool LLSelectMgr::selectionMove(const LLVector3& displ, + F32 roll, F32 pitch, F32 yaw, U32 update_type) +{ + if (update_type == UPD_NONE) + { + return false; + } + + LLVector3 displ_global; + bool update_success = true; + bool update_position = update_type & UPD_POSITION; + bool update_rotation = update_type & UPD_ROTATION; + const bool noedit_linked_parts = !gSavedSettings.getBOOL("EditLinkedParts"); + + if (update_position) + { + // calculate the distance of the object closest to the camera origin + F32 min_dist_squared = F32_MAX; // value will be overridden in the loop + + LLVector3 obj_pos; + for (LLObjectSelection::root_iterator it = getSelection()->root_begin(); + it != getSelection()->root_end(); ++it) + { + obj_pos = (*it)->getObject()->getPositionEdit(); + + F32 obj_dist_squared = dist_vec_squared(obj_pos, LLViewerCamera::getInstance()->getOrigin()); + if (obj_dist_squared < min_dist_squared) + { + min_dist_squared = obj_dist_squared; + } + } + + // factor the distance into the displacement vector. This will get us + // equally visible movements for both close and far away selections. + F32 min_dist = sqrt((F32) sqrtf(min_dist_squared)) / 2; + displ_global.setVec(displ.mV[0] * min_dist, + displ.mV[1] * min_dist, + displ.mV[2] * min_dist); + + // equates to: Displ_global = Displ * M_cam_axes_in_global_frame + displ_global = LLViewerCamera::getInstance()->rotateToAbsolute(displ_global); + } + + LLQuaternion new_rot; + if (update_rotation) + { + // let's calculate the rotation around each camera axes + LLQuaternion qx(roll, LLViewerCamera::getInstance()->getAtAxis()); + LLQuaternion qy(pitch, LLViewerCamera::getInstance()->getLeftAxis()); + LLQuaternion qz(yaw, LLViewerCamera::getInstance()->getUpAxis()); + new_rot.setQuat(qx * qy * qz); + } + + LLViewerObject *obj; + S32 obj_count = getSelection()->getObjectCount(); + for (LLObjectSelection::root_iterator it = getSelection()->root_begin(); + it != getSelection()->root_end(); ++it ) + { + obj = (*it)->getObject(); + bool enable_pos = false, enable_rot = false; + bool perm_move = obj->permMove() && !obj->isPermanentEnforced(); + bool perm_mod = obj->permModify(); + + LLVector3d sel_center(getSelectionCenterGlobal()); + + if (update_rotation) + { + enable_rot = perm_move + && ((perm_mod && !obj->isAttachment()) || noedit_linked_parts); + + if (enable_rot) + { + int children_count = obj->getChildren().size(); + if (obj_count > 1 && children_count > 0) + { + // for linked sets, rotate around the group center + const LLVector3 t(obj->getPositionGlobal() - sel_center); + + // Ra = T x R x T^-1 + LLMatrix4 mt; mt.setTranslation(t); + const LLMatrix4 mnew_rot(new_rot); + LLMatrix4 mt_1; mt_1.setTranslation(-t); + mt *= mnew_rot; + mt *= mt_1; + + // Rfin = Rcur * Ra + obj->setRotation(obj->getRotationEdit() * mt.quaternion()); + displ_global += mt.getTranslation(); + } + else + { + obj->setRotation(obj->getRotationEdit() * new_rot); + } + } + else + { + update_success = false; + } + } + + if (update_position) + { + // establish if object can be moved or not + enable_pos = perm_move && !obj->isAttachment() + && (perm_mod || noedit_linked_parts); + + if (enable_pos) + { + obj->setPosition(obj->getPositionEdit() + displ_global); + } + else + { + update_success = false; + } + } + + if (enable_pos && enable_rot && obj->mDrawable.notNull()) + { + gPipeline.markMoved(obj->mDrawable, true); + } + } + + if (update_position && update_success && obj_count > 1) + { + updateSelectionCenter(); + } + + return update_success; +} + +void LLSelectMgr::sendSelectionMove() +{ + LLSelectNode *node = mSelectedObjects->getFirstRootNode(); + if (node == NULL) + { + return; + } + + //saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); + + U32 update_type = UPD_POSITION | UPD_ROTATION; + LLViewerRegion *last_region, *curr_region = node->getObject()->getRegion(); + S32 objects_in_this_packet = 0; + + // apply to linked objects if unable to select their individual parts + if (!gSavedSettings.getBOOL("EditLinkedParts") && !getTEMode()) + { + // tell simulator to apply to whole linked sets + update_type |= UPD_LINKED_SETS; + } + + // prepare first bulk message + gMessageSystem->newMessage("MultipleObjectUpdate"); + packAgentAndSessionID(&update_type); + + LLViewerObject *obj = NULL; + for (LLObjectSelection::root_iterator it = getSelection()->root_begin(); + it != getSelection()->root_end(); ++it) + { + obj = (*it)->getObject(); + + // note: following code adapted from sendListToRegions() (@3924) + last_region = curr_region; + curr_region = obj->getRegion(); + + // if not simulator or message too big + if (curr_region != last_region + || gMessageSystem->isSendFull(NULL) + || objects_in_this_packet >= MAX_OBJECTS_PER_PACKET) + { + // send sim the current message and start new one + gMessageSystem->sendReliable(last_region->getHost()); + objects_in_this_packet = 0; + gMessageSystem->newMessage("MultipleObjectUpdate"); + packAgentAndSessionID(&update_type); + } + + // add another instance of the body of data + packMultipleUpdate(*it, &update_type); + ++objects_in_this_packet; + } + + // flush remaining messages + if (gMessageSystem->getCurrentSendTotal() > 0) + { + gMessageSystem->sendReliable(curr_region->getHost()); + } + else + { + gMessageSystem->clearMessage(); + } + + //saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); +} + +template<> +bool LLCheckIdenticalFunctor<F32>::same(const F32& a, const F32& b, const F32& tolerance) +{ + F32 delta = (a - b); + F32 abs_delta = fabs(delta); + return abs_delta <= tolerance; +} + +#define DEF_DUMMY_CHECK_FUNCTOR(T) \ +template<> \ +bool LLCheckIdenticalFunctor<T>::same(const T& a, const T& b, const T& tolerance) \ +{ \ + (void)tolerance; \ + return a == b; \ +} + +DEF_DUMMY_CHECK_FUNCTOR(LLUUID) +DEF_DUMMY_CHECK_FUNCTOR(LLGLenum) +DEF_DUMMY_CHECK_FUNCTOR(LLTextureEntry) +DEF_DUMMY_CHECK_FUNCTOR(LLTextureEntry::e_texgen) +DEF_DUMMY_CHECK_FUNCTOR(bool) +DEF_DUMMY_CHECK_FUNCTOR(U8) +DEF_DUMMY_CHECK_FUNCTOR(int) +DEF_DUMMY_CHECK_FUNCTOR(LLColor4) +DEF_DUMMY_CHECK_FUNCTOR(LLMediaEntry) +DEF_DUMMY_CHECK_FUNCTOR(LLPointer<LLMaterial>) +DEF_DUMMY_CHECK_FUNCTOR(LLPointer<LLGLTFMaterial>) +DEF_DUMMY_CHECK_FUNCTOR(std::string) +DEF_DUMMY_CHECK_FUNCTOR(std::vector<std::string>) + +template<> +bool LLCheckIdenticalFunctor<class LLFace *>::same(class LLFace* const & a, class LLFace* const & b, class LLFace* const & tolerance) \ +{ \ + (void)tolerance; \ + return a == b; \ +} + |