/** * @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 #include #include 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 struct LLSelectedTEGetFunctor { virtual ~LLSelectedTEGetFunctor() {}; virtual T get(LLViewerObject* object, S32 te) = 0; }; template 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 > 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 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 mSavedColors; std::vector mSavedShinyColors; uuid_vec_t mSavedTextures; uuid_vec_t mSavedGLTFMaterialIds; gltf_materials_vec_t mSavedGLTFOverrideMaterials; std::vector mTextureScaleRatios; std::vector< std::vector > mGLTFScaleRatios; std::vector mSilhouetteVertices; // array of vertices to render silhouette of object std::vector mSilhouetteNormals; // array of normals to render silhouette of object bool mSilhouetteExists; // need to generate silhouette? S32 mSelectedGLTFNode = -1; S32 mSelectedGLTFPrimitive = -1; protected: LLPointer mObject; S32 mTESelectMask; S32 mLastTESelected; }; class LLObjectSelection : public LLRefCount { friend class LLSelectMgr; friend class LLSafeHandle; friend class LLSelectionCallbackData; protected: ~LLObjectSelection(); public: typedef std::list list_t; // Iterators struct is_non_null { bool operator()(LLSelectNode* node) { return (node->getObject() != NULL); } }; typedef boost::filter_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 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 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 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 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 bool getSelectedTEValue(LLSelectedTEGetFunctor* func, T& res, bool has_tolerance = false, T tolerance = T()); template bool isMultipleTEValue(LLSelectedTEGetFunctor* 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 mPrimaryObject; std::map, LLSelectNode*> mSelectNodeMap; ESelectType mSelectType; }; typedef LLSafeHandle LLObjectSelectionHandle; // Build time optimization, generate this once in .cpp file #ifndef LLSELECTMGR_CPP extern template class LLSelectMgr* LLSingleton::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 { 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 mHideSelectedObjects; LLCachedControl mRenderHighlightSelections; LLCachedControl mAllowSelectAvatar; LLCachedControl 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 mObject; }; // Avatar overrides should persist even after selection // was removed as long as edit floater is up typedef std::map 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& 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& 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 ¤t_zoom) const; void updatePointAt(); // Internal list maintenance functions. TODO: Make these private! void remove(std::vector& 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& 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& 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 mSilhouetteImagep; LLObjectSelectionHandle mSelectedObjects; LLObjectSelectionHandle mHoverObjects; LLObjectSelectionHandle mHighlightedObjects; std::set > 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 mPauseRequests; }; // *DEPRECATED: For callbacks or observers, use // LLSelectMgr::getInstance()->mUpdateSignal.connect( callback ) // Update subscribers to the selection list void dialog_refresh_all(); // Templates //----------------------------------------------------------------------------- // getSelectedTEValue //----------------------------------------------------------------------------- template bool LLObjectSelection::getSelectedTEValue(LLSelectedTEGetFunctor* 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::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 bool LLObjectSelection::isMultipleTEValue(LLSelectedTEGetFunctor* 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