phoenix-firestorm/indra/newview/llselectmgr.h

1071 lines
42 KiB
C++

/**
* @file llselectmgr.h
* @brief A manager for selected objects and TEs.
*
* $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$
*/
#ifndef LL_LLSELECTMGR_H
#define LL_LLSELECTMGR_H
#include "llcharacter.h"
#include "lleditmenuhandler.h"
#include "llundo.h"
#include "lluuid.h"
#include "llpointer.h"
#include "llsafehandle.h"
#include "llsaleinfo.h"
#include "llcategory.h"
#include "v3dmath.h"
#include "llquaternion.h"
#include "llcoord.h"
#include "llframetimer.h"
#include "llbbox.h"
#include "llpermissions.h"
#include "llcontrol.h"
#include "llviewerobject.h" // LLObjectSelection::getSelectedTEValue template
#include "llmaterial.h"
#include "lluicolor.h"
#include <deque>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/signals2.hpp>
class LLMessageSystem;
class LLViewerTexture;
class LLColor4;
class LLVector3;
class LLSelectNode;
const U8 UPD_NONE = 0x00;
const U8 UPD_POSITION = 0x01;
const U8 UPD_ROTATION = 0x02;
const U8 UPD_SCALE = 0x04;
const U8 UPD_LINKED_SETS = 0x08;
const U8 UPD_UNIFORM = 0x10; // used with UPD_SCALE
// This is used by the DeRezObject message to determine where to put
// derezed tasks.
enum EDeRezDestination
{
DRD_SAVE_INTO_AGENT_INVENTORY = 0,
DRD_ACQUIRE_TO_AGENT_INVENTORY = 1, // try to leave copy in world
DRD_SAVE_INTO_TASK_INVENTORY = 2,
DRD_ATTACHMENT = 3,
DRD_TAKE_INTO_AGENT_INVENTORY = 4, // delete from world
DRD_FORCE_TO_GOD_INVENTORY = 5, // force take copy
DRD_TRASH = 6,
DRD_ATTACHMENT_TO_INV = 7,
DRD_ATTACHMENT_EXISTS = 8,
DRD_RETURN_TO_OWNER = 9, // back to owner's inventory
DRD_RETURN_TO_LAST_OWNER = 10, // deeded object back to last owner's inventory
DRD_COUNT = 11
};
const S32 SELECT_ALL_TES = -1;
const S32 SELECT_MAX_TES = 32;
// Do something to all objects in the selection manager.
// The bool return value can be used to indicate if all
// objects are identical (gathering information) or if
// the operation was successful.
struct LLSelectedObjectFunctor
{
virtual ~LLSelectedObjectFunctor() {};
virtual bool apply(LLViewerObject* object) = 0;
};
// Do something to all select nodes in the selection manager.
// The bool return value can be used to indicate if all
// objects are identical (gathering information) or if
// the operation was successful.
struct LLSelectedNodeFunctor
{
virtual ~LLSelectedNodeFunctor() {};
virtual bool apply(LLSelectNode* node) = 0;
};
struct LLSelectedTEFunctor
{
virtual ~LLSelectedTEFunctor() {};
virtual bool apply(LLViewerObject* object, S32 face) = 0;
};
struct LLSelectedTEMaterialFunctor
{
virtual ~LLSelectedTEMaterialFunctor() {};
virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) = 0;
};
template <typename T> struct LLSelectedTEGetFunctor
{
virtual ~LLSelectedTEGetFunctor() {};
virtual T get(LLViewerObject* object, S32 te) = 0;
};
template <typename T> struct LLCheckIdenticalFunctor
{
static bool same(const T& a, const T& b, const T& tolerance);
};
typedef enum e_send_type
{
SEND_ONLY_ROOTS,
SEND_INDIVIDUALS,
SEND_ROOTS_FIRST, // useful for serial undos on linked sets
SEND_CHILDREN_FIRST // useful for serial transforms of linked sets
} ESendType;
typedef enum e_grid_mode
{
GRID_MODE_WORLD,
GRID_MODE_LOCAL,
GRID_MODE_REF_OBJECT
} EGridMode;
typedef enum e_action_type
{
SELECT_ACTION_TYPE_BEGIN,
SELECT_ACTION_TYPE_PICK,
SELECT_ACTION_TYPE_MOVE,
SELECT_ACTION_TYPE_ROTATE,
SELECT_ACTION_TYPE_SCALE,
NUM_ACTION_TYPES
}EActionType;
typedef enum e_selection_type
{
SELECT_TYPE_WORLD,
SELECT_TYPE_ATTACHMENT,
SELECT_TYPE_HUD
}ESelectType;
typedef std::vector<LLPointer<LLGLTFMaterial> > gltf_materials_vec_t;
const S32 TE_SELECT_MASK_ALL = 0xFFFFFFFF;
// Contains information about a selected object, particularly which TEs are selected.
class LLSelectNode
{
public:
LLSelectNode(LLViewerObject* object, bool do_glow);
LLSelectNode(const LLSelectNode& nodep);
~LLSelectNode();
void selectAllTEs(bool b);
void selectTE(S32 te_index, bool selected);
void selectGLTFNode(S32 node_index, S32 primitive_index, bool selected);
bool isTESelected(S32 te_index) const;
bool hasSelectedTE() const { return TE_SELECT_MASK_ALL & mTESelectMask; }
S32 getLastSelectedTE() const;
S32 getLastOperatedTE() const { return mLastTESelected; }
S32 getTESelectMask() { return mTESelectMask; }
void renderOneSilhouette(const LLColor4 &color);
void setTransient(bool transient) { mTransient = transient; }
bool isTransient() const { return mTransient; }
LLViewerObject* getObject();
void setObject(LLViewerObject* object);
// *NOTE: invalidate stored textures and colors when # faces change
// Used by tools floater's color/texture pickers to restore changes
void saveColors();
void saveShinyColors();
void saveTextures(const uuid_vec_t& textures);
void saveTextureScaleRatios(LLRender::eTexIndex index_to_query);
// GLTF materials are applied to objects by ids,
// overrides get applied on top of materials resulting in
// final gltf material that users see.
// Ids get applied and restored by tools floater,
// overrides get applied in live material editor
// @param override_materials' content will be copied to not
// affect originals
void saveGLTFMaterials(const uuid_vec_t& materials, const gltf_materials_vec_t& override_materials);
bool allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const;
public:
bool mIndividualSelection; // For root objects and objects individually selected
bool mTransient;
bool mValid; // is extra information valid?
LLPermissions* mPermissions;
LLSaleInfo mSaleInfo;
LLAggregatePermissions mAggregatePerm;
LLAggregatePermissions mAggregateTexturePerm;
LLAggregatePermissions mAggregateTexturePermOwner;
std::string mName;
std::string mDescription;
LLCategory mCategory;
S16 mInventorySerial;
LLVector3 mSavedPositionLocal; // for interactively modifying object position
LLVector3 mLastPositionLocal;
LLVector3 mLastMoveLocal;
LLVector3d mSavedPositionGlobal; // for interactively modifying object position
LLVector3 mSavedScale; // for interactively modifying object scale
LLVector3 mLastScale;
LLQuaternion mSavedRotation; // for interactively modifying object rotation
LLQuaternion mLastRotation;
bool mDuplicated;
LLVector3d mDuplicatePos;
LLQuaternion mDuplicateRot;
LLUUID mItemID;
LLUUID mFolderID;
LLUUID mFromTaskID;
std::string mTouchName;
std::string mSitName;
U64 mCreationDate;
std::vector<LLColor4> mSavedColors;
std::vector<LLColor4> mSavedShinyColors;
uuid_vec_t mSavedTextures;
uuid_vec_t mSavedGLTFMaterialIds;
gltf_materials_vec_t mSavedGLTFOverrideMaterials;
std::vector<LLVector3> mTextureScaleRatios;
std::vector< std::vector<LLVector3> > mGLTFScaleRatios;
std::vector< std::vector<LLVector2> > mGLTFScales;
std::vector< std::vector<LLVector2> > mGLTFOffsets;
std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
bool mSilhouetteExists; // need to generate silhouette?
S32 mSelectedGLTFNode = -1;
S32 mSelectedGLTFPrimitive = -1;
protected:
LLPointer<LLViewerObject> mObject;
S32 mTESelectMask;
S32 mLastTESelected;
};
class LLObjectSelection : public LLRefCount
{
friend class LLSelectMgr;
friend class LLSafeHandle<LLObjectSelection>;
friend class LLSelectionCallbackData;
protected:
~LLObjectSelection();
public:
typedef std::list<LLSelectNode*> list_t;
// Iterators
struct is_non_null
{
bool operator()(LLSelectNode* node)
{
return (node->getObject() != NULL);
}
};
typedef boost::filter_iterator<is_non_null, list_t::iterator > iterator;
iterator begin() { return iterator(mList.begin(), mList.end()); }
iterator end() { return iterator(mList.end(), mList.end()); }
struct is_valid
{
bool operator()(LLSelectNode* node)
{
return (node->getObject() != NULL) && node->mValid;
}
};
typedef boost::filter_iterator<is_valid, list_t::iterator > valid_iterator;
valid_iterator valid_begin() { return valid_iterator(mList.begin(), mList.end()); }
valid_iterator valid_end() { return valid_iterator(mList.end(), mList.end()); }
struct is_root
{
bool operator()(LLSelectNode* node);
};
typedef boost::filter_iterator<is_root, list_t::iterator > root_iterator;
root_iterator root_begin() { return root_iterator(mList.begin(), mList.end()); }
root_iterator root_end() { return root_iterator(mList.end(), mList.end()); }
struct is_valid_root
{
bool operator()(LLSelectNode* node);
};
typedef boost::filter_iterator<is_valid_root, list_t::iterator > valid_root_iterator;
valid_root_iterator valid_root_begin() { return valid_root_iterator(mList.begin(), mList.end()); }
valid_root_iterator valid_root_end() { return valid_root_iterator(mList.end(), mList.end()); }
struct is_root_object
{
bool operator()(LLSelectNode* node);
};
typedef boost::filter_iterator<is_root_object, list_t::iterator > root_object_iterator;
root_object_iterator root_object_begin() { return root_object_iterator(mList.begin(), mList.end()); }
root_object_iterator root_object_end() { return root_object_iterator(mList.end(), mList.end()); }
public:
LLObjectSelection();
void updateEffects();
bool isEmpty() const;
LLSelectNode* getFirstNode(LLSelectedNodeFunctor* func = NULL);
LLSelectNode* getFirstRootNode(LLSelectedNodeFunctor* func = NULL, bool non_root_ok = false);
LLViewerObject* getFirstSelectedObject(LLSelectedNodeFunctor* func, bool get_parent = false);
LLViewerObject* getFirstObject();
LLViewerObject* getFirstRootObject(bool non_root_ok = false);
LLSelectNode* getFirstMoveableNode(bool get_root_first = false);
LLViewerObject* getFirstEditableObject(bool get_parent = false);
LLViewerObject* getFirstCopyableObject(bool get_parent = false);
LLViewerObject* getFirstDeleteableObject();
LLViewerObject* getFirstMoveableObject(bool get_parent = false);
LLViewerObject* getFirstUndoEnabledObject(bool get_parent = false);
/// Return the object that lead to this selection, possible a child
LLViewerObject* getPrimaryObject() { return mPrimaryObject; }
// iterate through texture entries
template <typename T> bool getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res, bool has_tolerance = false, T tolerance = T());
template <typename T> bool isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value);
S32 getNumNodes();
LLSelectNode* findNode(LLViewerObject* objectp);
// count members
S32 getObjectCount();
F32 getSelectedObjectCost();
F32 getSelectedLinksetCost();
F32 getSelectedPhysicsCost();
F32 getSelectedLinksetPhysicsCost();
S32 getSelectedObjectRenderCost();
F32 getSelectedObjectStreamingCost(S32* total_bytes = NULL, S32* visible_bytes = NULL);
U32 getSelectedObjectTriangleCount(S32* vcount = NULL);
S32 getTECount();
S32 getRootObjectCount();
bool isMultipleTESelected();
bool contains(LLViewerObject* object);
bool contains(LLViewerObject* object, S32 te);
// returns true is any node is currenly worn as an attachment
bool isAttachment();
bool checkAnimatedObjectEstTris();
bool checkAnimatedObjectLinkable();
// Apply functors to various subsets of the selected objects
// If firstonly is false, returns the AND of all apply() calls.
// Else returns true immediately if any apply() call succeeds (i.e. OR with early exit)
bool applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly = false);
bool applyToObjects(LLSelectedObjectFunctor* func);
bool applyToTEs(LLSelectedTEFunctor* func, bool firstonly = false);
bool applyToRootNodes(LLSelectedNodeFunctor* func, bool firstonly = false);
bool applyToNodes(LLSelectedNodeFunctor* func, bool firstonly = false);
/*
* Used to apply (no-copy) textures to the selected object or
* selected face/faces of the object.
* This method moves (no-copy) texture to the object's inventory
* and doesn't make copy of the texture for each face.
* Then this only texture is used for all selected faces.
*/
void applyNoCopyTextureToTEs(LLViewerInventoryItem* item);
/*
* Multi-purpose function for applying PBR materials to the
* selected object or faces, any combination of copy/mod/transfer
* permission restrictions. This method moves the restricted
* material to the object's inventory and doesn't make a copy of the
* material for each face. Then this only material is used for
* all selected faces.
* Returns false if applying the material failed on one or more selected
* faces.
*/
bool applyRestrictedPbrMaterialToTEs(LLViewerInventoryItem* item);
ESelectType getSelectType() const { return mSelectType; }
private:
void addNode(LLSelectNode *nodep);
void addNodeAtEnd(LLSelectNode *nodep);
void moveNodeToFront(LLSelectNode *nodep);
void removeNode(LLSelectNode *nodep);
void deleteAllNodes();
void cleanupNodes();
private:
list_t mList;
const LLObjectSelection &operator=(const LLObjectSelection &);
LLPointer<LLViewerObject> mPrimaryObject;
std::map<LLPointer<LLViewerObject>, LLSelectNode*> mSelectNodeMap;
ESelectType mSelectType;
};
typedef LLSafeHandle<LLObjectSelection> LLObjectSelectionHandle;
// Build time optimization, generate this once in .cpp file
#ifndef LLSELECTMGR_CPP
extern template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance();
#endif
// For use with getFirstTest()
struct LLSelectGetFirstTest;
// temporary storage, Ex: to attach objects after autopilot
class LLSelectionCallbackData
{
public:
LLSelectionCallbackData();
LLObjectSelectionHandle getSelection() { return mSelectedObjects; }
private:
LLObjectSelectionHandle mSelectedObjects;
};
class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr>
{
public:
static bool sRectSelectInclusive; // do we need to surround an object to pick it?
static bool sRenderHiddenSelections; // do we show selection silhouettes that are occluded?
static bool sRenderLightRadius; // do we show the radius of selected lights?
static F32 sHighlightThickness;
static F32 sHighlightUScale;
static F32 sHighlightVScale;
static F32 sHighlightAlpha;
static F32 sHighlightAlphaTest;
static F32 sHighlightUAnim;
static F32 sHighlightVAnim;
static LLUIColor sSilhouetteParentColor;
static LLUIColor sSilhouetteChildColor;
static LLUIColor sHighlightParentColor;
static LLUIColor sHighlightChildColor;
static LLUIColor sHighlightInspectColor;
static LLUIColor sContextSilhouetteColor;
LLCachedControl<bool> mHideSelectedObjects;
LLCachedControl<bool> mRenderHighlightSelections;
LLCachedControl<bool> mAllowSelectAvatar;
LLCachedControl<bool> mDebugSelectMgr;
public:
LLSelectMgr();
~LLSelectMgr();
static void cleanupGlobals();
// LLEditMenuHandler interface
virtual bool canUndo() const;
virtual void undo();
virtual bool canRedo() const;
virtual void redo();
virtual bool canDoDelete() const;
virtual void doDelete();
virtual void deselect();
virtual bool canDeselect() const;
virtual void duplicate();
virtual bool canDuplicate() const;
void clearSelections();
void update();
void updateEffects(); // Update HUD effects
// When we edit object's position/rotation/scale we set local
// overrides and ignore any updates (override received valeus).
// When we send data to server, we send local values and reset
// overrides
void resetObjectOverrides();
void resetObjectOverrides(LLObjectSelectionHandle selected_handle);
void overrideObjectUpdates();
void resetAvatarOverrides();
void overrideAvatarUpdates();
struct AvatarPositionOverride
{
AvatarPositionOverride();
AvatarPositionOverride(LLVector3 &vec, LLQuaternion &quat, LLViewerObject *obj) :
mLastPositionLocal(vec),
mLastRotation(quat),
mObject(obj)
{
}
LLVector3 mLastPositionLocal;
LLQuaternion mLastRotation;
LLPointer<LLViewerObject> mObject;
};
// Avatar overrides should persist even after selection
// was removed as long as edit floater is up
typedef std::map<LLUUID, AvatarPositionOverride> uuid_av_override_map_t;
uuid_av_override_map_t mAvatarOverridesMap;
public:
// Returns the previous value of mForceSelection
bool setForceSelection(bool force);
////////////////////////////////////////////////////////////////
// Selection methods
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
// Add
////////////////////////////////////////////////////////////////
// This method is meant to select an object, and then select all
// of the ancestors and descendants. This should be the normal behavior.
//
// *NOTE: You must hold on to the object selection handle, otherwise
// the objects will be automatically deselected in 1 frame.
LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, bool add_to_end = false, bool ignore_select_owned = false);
// For when you want just a child object.
LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES, S32 gltf_node = -1, S32 gltf_primitive = -1);
// Same as above, but takes a list of objects. Used by rectangle select.
LLObjectSelectionHandle selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list, bool send_to_sim = true);
// converts all objects currently highlighted to a selection, and returns it
LLObjectSelectionHandle selectHighlightedObjects();
LLObjectSelectionHandle setHoverObject(LLViewerObject *objectp, S32 face = -1);
LLSelectNode *getHoverNode();
LLSelectNode *getPrimaryHoverNode();
void highlightObjectOnly(LLViewerObject *objectp);
void highlightObjectAndFamily(LLViewerObject *objectp);
void highlightObjectAndFamily(const std::vector<LLViewerObject*>& list);
////////////////////////////////////////////////////////////////
// Remove
////////////////////////////////////////////////////////////////
void deselectObjectOnly(LLViewerObject* object, bool send_to_sim = true);
void deselectObjectAndFamily(LLViewerObject* object, bool send_to_sim = true, bool include_entire_object = false);
// Send deselect messages to simulator, then clear the list
void deselectAll();
void deselectAllForStandingUp();
// deselect only if nothing else currently referencing the selection
void deselectUnused();
// Deselect if the selection center is too far away from the agent.
void deselectAllIfTooFar();
// Removes all highlighted objects from current selection
void deselectHighlightedObjects();
void unhighlightObjectOnly(LLViewerObject *objectp);
void unhighlightObjectAndFamily(LLViewerObject *objectp);
void unhighlightAll();
bool removeObjectFromSelections(const LLUUID &id);
////////////////////////////////////////////////////////////////
// Selection editing
////////////////////////////////////////////////////////////////
bool linkObjects();
bool unlinkObjects();
void confirmUnlinkObjects(const LLSD& notification, const LLSD& response);
bool enableLinkObjects();
bool enableUnlinkObjects();
////////////////////////////////////////////////////////////////
// Selection accessors
////////////////////////////////////////////////////////////////
LLObjectSelectionHandle getSelection() { return mSelectedObjects; }
// right now this just renders the selection with root/child colors instead of a single color
LLObjectSelectionHandle getEditSelection() { convertTransient(); return mSelectedObjects; }
LLObjectSelectionHandle getHighlightedObjects() { return mHighlightedObjects; }
////////////////////////////////////////////////////////////////
// Grid manipulation
////////////////////////////////////////////////////////////////
void addGridObject(LLViewerObject* objectp);
void clearGridObjects();
void setGridMode(EGridMode mode);
EGridMode getGridMode() { return mGridMode; }
void getGrid(LLVector3& origin, LLQuaternion& rotation, LLVector3 &scale, bool for_snap_guides = false);
bool getTEMode() const { return mTEMode; }
void setTEMode(bool b) { mTEMode = b; }
bool shouldShowSelection() const { return mShowSelection; }
LLBBox getBBoxOfSelection() const;
LLBBox getSavedBBoxOfSelection() const { return mSavedSelectionBBox; }
void dump();
void cleanup();
void updateSilhouettes();
void renderSilhouettes(bool for_hud);
void enableSilhouette(bool enable) { mRenderSilhouettes = enable; }
////////////////////////////////////////////////////////////////
// Utility functions that operate on the current selection
////////////////////////////////////////////////////////////////
void saveSelectedObjectTransform(EActionType action_type);
void saveSelectedObjectColors();
void saveSelectedShinyColors();
void saveSelectedObjectTextures();
void selectionUpdatePhysics(bool use_physics);
void selectionUpdateTemporary(bool is_temporary);
void selectionUpdatePhantom(bool is_ghost);
void selectionDump();
bool selectionAllPCode(LLPCode code); // all objects have this PCode
bool selectionGetClickAction(U8 *out_action);
bool selectionGetIncludeInSearch(bool* include_in_search_out); // true if all selected objects have same
bool selectionGetGlow(F32 *glow);
void selectionSetPhysicsType(U8 type);
void selectionSetGravity(F32 gravity);
void selectionSetFriction(F32 friction);
void selectionSetDensity(F32 density);
void selectionSetRestitution(F32 restitution);
void selectionSetMaterial(U8 material);
bool selectionSetImage(const LLUUID& imageid); // could be item or asset id
bool selectionSetGLTFMaterial(const LLUUID& mat_id); // material id only
void selectionSetColor(const LLColor4 &color);
void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels
void selectionSetAlphaOnly(const F32 alpha); // Set only the alpha channel
void selectionRevertColors();
void selectionRevertShinyColors();
bool selectionRevertTextures();
void selectionRevertGLTFMaterials();
void selectionSetBumpmap( U8 bumpmap, const LLUUID &image_id );
void selectionSetTexGen( U8 texgen );
void selectionSetShiny( U8 shiny, const LLUUID &image_id );
void selectionSetFullbright( U8 fullbright );
void selectionSetMedia( U8 media_type, const LLSD &media_data );
void selectionSetClickAction(U8 action);
void selectionSetIncludeInSearch(bool include_in_search);
void selectionSetGlow(const F32 glow);
void selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func, int specific_te = -1);
void selectionRemoveMaterial();
void selectionSetObjectPermissions(U8 perm_field, bool set, U32 perm_mask, bool override = false);
void selectionSetObjectName(const std::string& name);
void selectionSetObjectDescription(const std::string& desc);
void selectionSetObjectCategory(const LLCategory& category);
void selectionSetObjectSaleInfo(const LLSaleInfo& sale_info);
void selectionTexScaleAutofit(F32 repeats_per_meter);
void adjustTexturesByScale(bool send_to_sim, bool stretch);
bool selectionMove(const LLVector3& displ, F32 rx, F32 ry, F32 rz,
U32 update_type);
void sendSelectionMove();
void sendGodlikeRequest(const std::string& request, const std::string& parameter);
// will make sure all selected object meet current criteria, or deselect them otherwise
void validateSelection();
// returns true if it is possible to select this object
bool canSelectObject(LLViewerObject* object, bool ignore_select_owned = false);
// Returns true if the viewer has information on all selected objects
bool selectGetAllRootsValid();
bool selectGetAllValid();
bool selectGetAllValidAndObjectsFound();
// returns true if you can modify all selected objects.
bool selectGetRootsModify();
bool selectGetModify();
// returns true if all objects are in same region
bool selectGetSameRegion();
// returns true if is all objects are non-permanent-enforced
bool selectGetRootsNonPermanentEnforced();
bool selectGetNonPermanentEnforced();
// returns true if is all objects are permanent
bool selectGetRootsPermanent();
bool selectGetPermanent();
// returns true if is all objects are character
bool selectGetRootsCharacter();
bool selectGetCharacter();
// returns true if is all objects are not permanent
bool selectGetRootsNonPathfinding();
bool selectGetNonPathfinding();
// returns true if is all objects are not permanent
bool selectGetRootsNonPermanent();
bool selectGetNonPermanent();
// returns true if is all objects are not character
bool selectGetRootsNonCharacter();
bool selectGetNonCharacter();
bool selectGetEditableLinksets();
bool selectGetViewableCharacters();
// returns true if selected objects can be transferred.
bool selectGetRootsTransfer();
// returns true if selected objects can be copied.
bool selectGetRootsCopy();
bool selectGetCreator(LLUUID& id, std::string& name); // true if all have same creator, returns id
bool selectGetOwner(LLUUID& id, std::string& name); // true if all objects have same owner, returns id
bool selectGetLastOwner(LLUUID& id, std::string& name); // true if all objects have same owner, returns id
// returns true if all are the same. id is stuffed with
// the value found if available.
bool selectGetGroup(LLUUID& id);
bool selectGetPerm( U8 which_perm, U32* mask_on, U32* mask_off); // true if all have data, returns two masks, each indicating which bits are all on and all off
bool selectIsGroupOwned(); // true if all root objects have valid data and are group owned.
// returns true if all the nodes are valid. Accumulates
// permissions in the parameter.
bool selectGetPermissions(LLPermissions& perm);
// returns true if all the nodes are valid. Depends onto "edit linked" state
// Children in linksets are a bit special - they require not only move permission
// but also modify if "edit linked" is set, since you move them relative to parent
bool selectGetEditMoveLinksetPermissions(bool &move, bool &modify);
// Get a bunch of useful sale information for the object(s) selected.
// "_mixed" is true if not all objects have the same setting.
void selectGetAggregateSaleInfo(U32 &num_for_sale,
bool &is_for_sale_mixed,
bool &is_sale_price_mixed,
S32 &total_sale_price,
S32 &individual_sale_price);
// returns true if all nodes are valid.
bool selectGetCategory(LLCategory& category);
// returns true if all nodes are valid. method also stores an
// accumulated sale info.
bool selectGetSaleInfo(LLSaleInfo& sale_info);
// returns true if all nodes are valid. fills passed in object
// with the aggregate permissions of the selection.
bool selectGetAggregatePermissions(LLAggregatePermissions& ag_perm);
// returns true if all nodes are valid. fills passed in object
// with the aggregate permissions for texture inventory items of the selection.
bool selectGetAggregateTexturePermissions(LLAggregatePermissions& ag_perm);
LLPermissions* findObjectPermissions(const LLViewerObject* object);
bool isMovableAvatarSelected();
void selectDelete(); // Delete on simulator
void selectForceDelete(); // just delete, no into trash
void selectDuplicate(const LLVector3& offset, bool select_copy); // Duplicate on simulator
void repeatDuplicate();
void 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);
void sendMultipleUpdate(U32 type); // Position, rotation, scale all in one
void sendOwner(const LLUUID& owner_id, const LLUUID& group_id, bool override = false);
void sendGroup(const LLUUID& group_id);
// Category ID is the UUID of the folder you want to contain the purchase.
// *NOTE: sale_info check doesn't 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
void sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info);
void sendAttach(U8 attachment_point, bool replace);
void sendAttach(LLObjectSelectionHandle selection_handle, U8 attachment_point, bool replace);
void sendDetach();
void sendDropAttachment();
void sendLink();
void sendDelink();
//void sendHinge(U8 type);
//void sendDehinge();
void sendSelect();
void requestObjectPropertiesFamily(LLViewerObject* object); // asks sim for creator, permissions, resources, etc.
static void processObjectProperties(LLMessageSystem *mesgsys, void **user_data);
static void processObjectPropertiesFamily(LLMessageSystem *mesgsys, void **user_data);
static void processForceObjectSelect(LLMessageSystem* msg, void**);
void requestGodInfo();
LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; }
void updateSelectionCenter();
void pauseAssociatedAvatars();
void resetAgentHUDZoom();
void setAgentHUDZoom(F32 target_zoom, F32 current_zoom);
void getAgentHUDZoom(F32 &target_zoom, F32 &current_zoom) const;
void updatePointAt();
void clearWaterExclusion();
// Internal list maintenance functions. TODO: Make these private!
void remove(std::vector<LLViewerObject*>& objects);
void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true);
void removeAll();
void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, bool undoable = true, S32 gltf_node = -1, S32 gltf_primitive = -1);
void promoteSelectionToRoot();
void demoteSelectionToIndividuals();
private:
void convertTransient(); // converts temporarily selected objects to full-fledged selections
ESelectType getSelectTypeForObject(LLViewerObject* object);
void addAsFamily(std::vector<LLViewerObject*>& objects, bool add_to_end = false);
void generateSilhouette(LLSelectNode *nodep, const LLVector3& view_point);
void updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects);
// Send one message to each region containing an object on selection list.
void 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);
void 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);
static void packAgentID( void *);
static void packAgentAndSessionID(void* user_data);
static void packAgentAndGroupID(void* user_data);
static void packAgentAndSessionAndGroupID(void* user_data);
static void packAgentIDAndSessionAndAttachment(void*);
static void packAgentGroupAndCatID(void*);
static void packDeleteHeader(void* userdata);
static void packDeRezHeader(void* user_data);
static void packObjectID( LLSelectNode* node, void *);
static void packObjectIDAsParam(LLSelectNode* node, void *);
static void packObjectIDAndRotation(LLSelectNode* node, void *);
static void packObjectLocalID(LLSelectNode* node, void *);
static void packObjectClickAction(LLSelectNode* node, void* data);
static void packObjectIncludeInSearch(LLSelectNode* node, void* data);
static void packObjectName(LLSelectNode* node, void* user_data);
static void packObjectDescription(LLSelectNode* node, void* user_data);
static void packObjectCategory(LLSelectNode* node, void* user_data);
static void packObjectSaleInfo(LLSelectNode* node, void* user_data);
static void packBuyObjectIDs(LLSelectNode* node, void* user_data);
static void packDuplicate( LLSelectNode* node, void *duplicate_data);
static void packDuplicateHeader(void*);
static void packDuplicateOnRayHead(void *user_data);
static void packPermissions(LLSelectNode* node, void *user_data);
static void packDeselect( LLSelectNode* node, void *user_data);
static void packMultipleUpdate(LLSelectNode* node, void *user_data);
static void packPhysics(LLSelectNode* node, void *user_data);
static void packShape(LLSelectNode* node, void *user_data);
static void packOwnerHead(void *user_data);
static void packHingeHead(void *user_data);
static void packPermissionsHead(void* user_data);
static void packGodlikeHead(void* user_data);
static void logNoOp(LLSelectNode* node, void *user_data);
static void logAttachmentRequest(LLSelectNode* node, void *user_data);
static void logDetachRequest(LLSelectNode* node, void *user_data);
static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle);
// Get the first ID that matches test and whether or not all ids are identical in selected objects.
void getFirst(LLSelectGetFirstTest* test);
public:
// Observer/callback support for when object selection changes or
// properties are received/updated
typedef boost::signals2::signal< void ()> update_signal_t;
update_signal_t mUpdateSignal;
private:
LLPointer<LLViewerTexture> mSilhouetteImagep;
LLObjectSelectionHandle mSelectedObjects;
LLObjectSelectionHandle mHoverObjects;
LLObjectSelectionHandle mHighlightedObjects;
std::set<LLPointer<LLViewerObject> > mRectSelectedObjects;
LLObjectSelection mGridObjects;
LLQuaternion mGridRotation;
LLVector3 mGridOrigin;
LLVector3 mGridScale;
EGridMode mGridMode;
bool mTEMode; // render te
LLRender::eTexIndex mTextureChannel; // diff, norm, or spec, depending on UI editing mode
LLVector3d mSelectionCenterGlobal;
LLBBox mSelectionBBox;
LLVector3d mLastSentSelectionCenterGlobal;
bool mShowSelection; // do we send the selection center name value and do we animate this selection?
LLVector3d mLastCameraPos; // camera position from last generation of selection silhouette
bool mRenderSilhouettes; // do we render the silhouette
LLBBox mSavedSelectionBBox;
LLFrameTimer mEffectsTimer;
bool mForceSelection;
std::vector<LLAnimPauseRequest> mPauseRequests;
boost::signals2::connection mSlectionLodModChangedConnection;
};
// *DEPRECATED: For callbacks or observers, use
// LLSelectMgr::getInstance()->mUpdateSignal.connect( callback )
// Update subscribers to the selection list
void dialog_refresh_all();
// Templates
//-----------------------------------------------------------------------------
// getSelectedTEValue
//-----------------------------------------------------------------------------
template <typename T> bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGetFunctor<T>* func, T& res, bool has_tolerance, T tolerance)
{
bool have_first = false;
bool have_selected = false;
T selected_value = T();
// Now iterate through all TEs to test for sameness
bool identical = true;
for (iterator iter = begin(); iter != end(); iter++)
{
LLSelectNode* node = *iter;
LLViewerObject* object = node->getObject();
S32 selected_te = -1;
if (object == getPrimaryObject())
{
selected_te = node->getLastSelectedTE();
}
for (S32 te = 0; te < object->getNumTEs(); ++te)
{
if (!node->isTESelected(te))
{
continue;
}
T value = func->get(object, te);
if (!have_first)
{
have_first = true;
if (!have_selected)
{
selected_value = value;
}
}
else
{
if ( value != selected_value )
{
if (!has_tolerance)
{
identical = false;
}
else if (!LLCheckIdenticalFunctor<T>::same(value, selected_value, tolerance))
{
identical = false;
}
}
if (te == selected_te)
{
selected_value = value;
have_selected = true;
}
}
}
if (!identical && have_selected)
{
break;
}
}
if (have_first || have_selected)
{
res = selected_value;
}
return identical;
}
// Templates
//-----------------------------------------------------------------------------
// isMultipleTEValue iterate through all TEs and test for uniqueness
// with certain return value ignored when performing the test.
// e.g. when testing if the selection has a unique non-empty homeurl :
// you can set ignore_value = "" and it will only compare among the non-empty
// homeUrls and ignore the empty ones.
//-----------------------------------------------------------------------------
template <typename T> bool LLObjectSelection::isMultipleTEValue(LLSelectedTEGetFunctor<T>* func, const T& ignore_value)
{
bool have_first = false;
T selected_value = T();
// Now iterate through all TEs to test for sameness
bool unique = true;
for (iterator iter = begin(); iter != end(); iter++)
{
LLSelectNode* node = *iter;
LLViewerObject* object = node->getObject();
for (S32 te = 0; te < object->getNumTEs(); ++te)
{
if (!node->isTESelected(te))
{
continue;
}
T value = func->get(object, te);
if(value == ignore_value)
{
continue;
}
if (!have_first)
{
have_first = true;
}
else
{
if (value !=selected_value )
{
unique = false;
return !unique;
}
}
}
}
return !unique;
}
#endif