aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llselectmgr.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llselectmgr.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llselectmgr.cpp')
-rw-r--r--linden/indra/newview/llselectmgr.cpp6761
1 files changed, 6761 insertions, 0 deletions
diff --git a/linden/indra/newview/llselectmgr.cpp b/linden/indra/newview/llselectmgr.cpp
new file mode 100644
index 0000000..9b13441
--- /dev/null
+++ b/linden/indra/newview/llselectmgr.cpp
@@ -0,0 +1,6761 @@
1/**
2 * @file llselectmgr.cpp
3 * @brief A manager for selected objects and faces.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30// file include
31#include "llselectmgr.h"
32
33// library includes
34#include "llcachename.h"
35#include "lldbstrings.h"
36#include "lleconomy.h"
37#include "llgl.h"
38#include "llpermissions.h"
39#include "llpermissionsflags.h"
40#include "llptrskiplist.h"
41#include "llundo.h"
42#include "lluuid.h"
43#include "llvolume.h"
44#include "message.h"
45#include "object_flags.h"
46#include "llquaternion.h"
47
48// viewer includes
49#include "llagent.h"
50#include "llviewerwindow.h"
51#include "lldrawable.h"
52#include "llfloaterinspect.h"
53#include "llfloaterproperties.h"
54#include "llfloaterrate.h"
55#include "llfloaterreporter.h"
56#include "llfloatertools.h"
57#include "llframetimer.h"
58#include "llhudeffecttrail.h"
59#include "llhudmanager.h"
60#include "llinventorymodel.h"
61#include "llmenugl.h"
62#include "llstatusbar.h"
63#include "llsurface.h"
64#include "lltool.h"
65#include "lltooldraganddrop.h"
66#include "lltoolmgr.h"
67#include "lltoolpie.h"
68#include "llui.h"
69#include "llviewercamera.h"
70#include "llviewercontrol.h"
71#include "llviewerimagelist.h"
72#include "llviewermenu.h"
73#include "llviewerobject.h"
74#include "llviewerobjectlist.h"
75#include "llviewerregion.h"
76#include "llviewerstats.h"
77#include "llvoavatar.h"
78#include "llvovolume.h"
79#include "pipeline.h"
80
81#include "llglheaders.h"
82
83//
84// Consts
85//
86
87const S32 NUM_SELECTION_UNDO_ENTRIES = 200;
88const F32 SILHOUETTE_UPDATE_THRESHOLD_SQUARED = 0.02f;
89const S32 OWNERSHIP_COST_PER_OBJECT = 10; // Must be the same as economy_constants.price_object_claim in the database.
90const S32 MAX_ACTION_QUEUE_SIZE = 20;
91const S32 MAX_SILS_PER_FRAME = 50;
92const S32 MAX_OBJECTS_PER_PACKET = 254;
93
94extern LLGlobalEconomy *gGlobalEconomy;
95extern LLUUID gLastHitObjectID;
96extern LLVector3d gLastHitObjectOffset;
97
98//
99// Globals
100//
101LLSelectMgr* gSelectMgr = NULL;
102
103BOOL gDebugSelectMgr = FALSE;
104
105BOOL gHideSelectedObjects = FALSE;
106BOOL gAllowSelectAvatar = FALSE;
107
108BOOL LLSelectMgr::sRectSelectInclusive = TRUE;
109BOOL LLSelectMgr::sRenderHiddenSelections = TRUE;
110BOOL LLSelectMgr::sRenderLightRadius = FALSE;
111F32 LLSelectMgr::sHighlightThickness = 0.f;
112F32 LLSelectMgr::sHighlightUScale = 0.f;
113F32 LLSelectMgr::sHighlightVScale = 0.f;
114F32 LLSelectMgr::sHighlightAlpha = 0.f;
115F32 LLSelectMgr::sHighlightAlphaTest = 0.f;
116F32 LLSelectMgr::sHighlightUAnim = 0.f;
117F32 LLSelectMgr::sHighlightVAnim = 0.f;
118LLColor4 LLSelectMgr::sSilhouetteParentColor;
119LLColor4 LLSelectMgr::sSilhouetteChildColor;
120LLColor4 LLSelectMgr::sHighlightInspectColor;
121LLColor4 LLSelectMgr::sHighlightParentColor;
122LLColor4 LLSelectMgr::sHighlightChildColor;
123LLColor4 LLSelectMgr::sContextSilhouetteColor;
124
125
126//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
127// struct LLDeRezInfo
128//
129// Used to keep track of important derez info.
130//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
131
132struct LLDeRezInfo
133{
134 EDeRezDestination mDestination;
135 LLUUID mDestinationID;
136 LLDeRezInfo(EDeRezDestination dest, const LLUUID& dest_id) :
137 mDestination(dest), mDestinationID(dest_id) {}
138};
139
140//
141// Imports
142//
143
144
145//
146// Functions
147//
148
149//-----------------------------------------------------------------------------
150// LLSelectMgr()
151//-----------------------------------------------------------------------------
152LLSelectMgr::LLSelectMgr()
153{
154 mTEMode = FALSE;
155 mLastCameraPos.clearVec();
156
157 sHighlightThickness = gSavedSettings.getF32("SelectionHighlightThickness");
158 sHighlightUScale = gSavedSettings.getF32("SelectionHighlightUScale");
159 sHighlightVScale = gSavedSettings.getF32("SelectionHighlightVScale");
160 sHighlightAlpha = gSavedSettings.getF32("SelectionHighlightAlpha");
161 sHighlightAlphaTest = gSavedSettings.getF32("SelectionHighlightAlphaTest");
162 sHighlightUAnim = gSavedSettings.getF32("SelectionHighlightUAnim");
163 sHighlightVAnim = gSavedSettings.getF32("SelectionHighlightVAnim");
164
165 sSilhouetteParentColor = gColors.getColor("SilhouetteParentColor");
166 sSilhouetteChildColor = gColors.getColor("SilhouetteChildColor");
167 sHighlightParentColor = gColors.getColor("HighlightParentColor");
168 sHighlightChildColor = gColors.getColor("HighlightChildColor");
169 sHighlightInspectColor = gColors.getColor("HighlightInspectColor");
170 sContextSilhouetteColor = gColors.getColor("ContextSilhouetteColor")*0.5f;
171
172 sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
173
174 mRenderSilhouettes = TRUE;
175
176 mGridMode = GRID_MODE_WORLD;
177 gSavedSettings.setS32("GridMode", (S32)GRID_MODE_WORLD);
178 mGridValid = FALSE;
179
180 mSelectType = SELECT_TYPE_WORLD;
181}
182
183
184//-----------------------------------------------------------------------------
185// ~LLSelectMgr()
186//-----------------------------------------------------------------------------
187LLSelectMgr::~LLSelectMgr()
188{
189 mHoverObjects.deleteAllNodes();
190 mSelectedObjects.deleteAllNodes();
191 mHighlightedObjects.deleteAllNodes();
192 mRectSelectedObjects.clear();
193 mGridObjects.deleteAllNodes();
194 mUndoQueue.clear();
195 mRedoQueue.clear();
196}
197
198bool LLSelectMgr::applyToObjects(LLSelectedObjectFunctor* func)
199{
200 bool result = true;
201 LLViewerObject* object;
202 for (object = getFirstObject(); object != NULL; object = getNextObject())
203 {
204 result = result && func->apply(object);
205 }
206 return result;
207}
208
209bool LLSelectMgr::applyToRootObjects(LLSelectedObjectFunctor* func)
210{
211 bool result = true;
212 LLViewerObject* object;
213 for (object = getFirstRootObject();
214 object != NULL;
215 object = getNextRootObject())
216 {
217 result = result && func->apply(object);
218 }
219 return result;
220}
221
222bool LLSelectMgr::applyToNodes(LLSelectedNodeFunctor *func)
223{
224 bool result = true;
225 LLSelectNode* node;
226 for (node = getFirstNode(); node != NULL; node = getNextNode())
227 {
228 result = result && func->apply(node);
229 }
230 return result;
231}
232
233void LLSelectMgr::updateEffects()
234{
235 if (mEffectsTimer.getElapsedTimeF32() > 1.f)
236 {
237 mSelectedObjects.updateEffects();
238 mEffectsTimer.reset();
239 }
240}
241
242//-----------------------------------------------------------------------------
243// Select just the object, not any other group members.
244//-----------------------------------------------------------------------------
245void LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face)
246{
247 llassert( object );
248
249 // Don't add an object that is already in the list
250 if (object->isSelected() ) {
251 // make sure point at position is updated
252 updatePointAt();
253 gEditMenuHandler = this;
254 return;
255 }
256
257 if (!canSelectObject(object))
258 {
259 //make_ui_sound("UISndInvalidOp");
260 return;
261 }
262
263 // llinfos << "Adding object to selected object list" << llendl;
264
265 // Place it in the list and tag it.
266 // This will refresh dialogs.
267 addAsIndividual(object, face);
268
269 // Stop the object from moving (this anticipates changes on the
270 // simulator in LLTask::userSelect)
271 // *FIX: shouldn't zero out these either
272 object->setVelocity(LLVector3::zero);
273 object->setAcceleration(LLVector3::zero);
274 //object->setAngularVelocity(LLVector3::zero);
275 object->resetRot();
276
277 // Always send to simulator, so you get a copy of the
278 // permissions structure back.
279 gMessageSystem->newMessageFast(_PREHASH_ObjectSelect);
280 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
281 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
282 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
283 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
284 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
285 LLViewerRegion* regionp = object->getRegion();
286 gMessageSystem->sendReliable( regionp->getHost());
287
288 updatePointAt();
289 updateSelectionCenter();
290 saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
291
292 // have selection manager handle edit menu immediately after
293 // user selects an object
294 if (getObjectCount())
295 {
296 gEditMenuHandler = this;
297 }
298}
299
300//-----------------------------------------------------------------------------
301// Select the object, parents and children.
302//-----------------------------------------------------------------------------
303void LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, BOOL add_to_end)
304{
305 llassert( obj );
306
307 // This may be incorrect if things weren't family selected before... - djs 07/08/02
308 // Don't add an object that is already in the list
309 if (obj->isSelected() )
310 {
311 // make sure pointat position is updated
312 updatePointAt();
313 gEditMenuHandler = this;
314 return;
315 }
316
317 if (!canSelectObject(obj))
318 {
319 //make_ui_sound("UISndInvalidOp");
320 return;
321 }
322
323 // Since we're selecting a family, start at the root, but
324 // don't include an avatar.
325 LLViewerObject* root = obj;
326
327 while(!root->isAvatar() && root->getParent() && !root->isJointChild())
328 {
329 LLViewerObject* parent = (LLViewerObject*)root->getParent();
330 if (parent->isAvatar())
331 {
332 break;
333 }
334 root = parent;
335 }
336
337 // Collect all of the objects
338 LLDynamicArray<LLViewerObject*> objects;
339
340 root->addThisAndNonJointChildren(objects);
341 addAsFamily(objects, add_to_end);
342
343 updateSelectionCenter();
344 saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
345 updatePointAt();
346
347 dialog_refresh_all();
348
349 // Always send to simulator, so you get a copy of the permissions
350 // structure back.
351 sendSelect();
352
353 // Stop the object from moving (this anticipates changes on the
354 // simulator in LLTask::userSelect)
355 root->setVelocity(LLVector3::zero);
356 root->setAcceleration(LLVector3::zero);
357 //root->setAngularVelocity(LLVector3::zero);
358 root->resetRot();
359
360 // leave component mode
361 if (!gSavedSettings.getBOOL("SelectLinkedSet"))
362 {
363 gSavedSettings.setBOOL("SelectLinkedSet", TRUE);
364 promoteSelectionToRoot();
365 }
366
367 // have selection manager handle edit menu immediately after
368 // user selects an object
369 if (getObjectCount())
370 {
371 gEditMenuHandler = this;
372 }
373}
374
375//-----------------------------------------------------------------------------
376// Select the object, parents and children.
377//-----------------------------------------------------------------------------
378void LLSelectMgr::selectObjectAndFamily(const LLDynamicArray<LLViewerObject*>& object_list,
379 BOOL send_to_sim)
380{
381 // Collect all of the objects, children included
382 LLDynamicArray<LLViewerObject*> objects;
383 LLViewerObject *object;
384 S32 i;
385
386 if (object_list.count() < 1) return;
387
388 // NOTE -- we add the objects in REVERSE ORDER
389 // to preserve the order in the mSelectedObjects list
390 for (i = object_list.count() - 1; i >= 0; i--)
391 {
392 object = object_list.get(i);
393
394 llassert( object );
395
396 if (!canSelectObject(object)) continue;
397
398 object->addThisAndNonJointChildren(objects);
399 addAsFamily(objects);
400
401 // Stop the object from moving (this anticipates changes on the
402 // simulator in LLTask::userSelect)
403 object->setVelocity(LLVector3::zero);
404 object->setAcceleration(LLVector3::zero);
405 //object->setAngularVelocity(LLVector3::zero);
406 object->resetRot();
407 }
408
409 updateSelectionCenter();
410 saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
411 updatePointAt();
412 dialog_refresh_all();
413
414 // Almost always send to simulator, so you get a copy of the permissions
415 // structure back.
416 // JC: The one case where you don't want to do this is if you're selecting
417 // all the objects on a sim.
418 if (send_to_sim)
419 {
420 sendSelect();
421 }
422
423 // leave component mode
424 if (!gSavedSettings.getBOOL("SelectLinkedSet"))
425 {
426 gSavedSettings.setBOOL("SelectLinkedSet", TRUE);
427 promoteSelectionToRoot();
428 }
429
430 // have selection manager handle edit menu immediately after
431 // user selects an object
432 if (getObjectCount())
433 {
434 gEditMenuHandler = this;
435 }
436}
437
438// Use for when the simulator kills an object. This version also
439// handles informing the current tool of the object's deletion.
440//
441// Caller needs to call dialog_refresh_all if necessary.
442BOOL LLSelectMgr::selectionRemoveObject(const LLUUID &id)
443{
444
445
446 BOOL object_found = FALSE;
447 LLTool *tool = NULL;
448 if (!gNoRender)
449 {
450 tool = gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) );
451
452 // It's possible that the tool is editing an object that is not selected
453 LLViewerObject* tool_editing_object = tool->getEditingObject();
454 if( tool_editing_object && tool_editing_object->mID == id)
455 {
456 tool->stopEditing();
457 object_found = TRUE;
458 }
459 }
460
461 // Iterate through selected objects list and kill the object
462 if( !object_found )
463 {
464 LLViewerObject* prevobjp = NULL;
465 for( LLViewerObject* tobjp = getFirstObject(); tobjp != NULL; tobjp = getNextObject() )
466 {
467 if (tobjp == prevobjp)
468 {
469 // Somehow we got stuck in an infinite loop... (DaveP)
470 // this logic is kind of twisted, not sure how this is happening, so...
471 llwarns << "Detected infinite loop #1 in LLSelectMgr::selectionRemoveObject:|" << llendl;
472 //MikeS. adding warning and comment...
473 //These infinite loops happen because the LLSelectMgr iteration routines are non-reentrant.
474 //deselectObjectAndFamily uses getFirstObject and getNextObject to mess with the array,
475 //resetting the arrays internal iterator state. This needs fixing BAD.
476 continue;
477 }
478 // It's possible the item being removed has an avatar sitting on it
479 // So remove the avatar that is sitting on the object.
480 if (tobjp->mID == id || tobjp->isAvatar())
481 {
482 if (!gNoRender)
483 {
484 tool->stopEditing();
485 }
486
487 // lose the selection, don't tell simulator, it knows
488 deselectObjectAndFamily(tobjp, FALSE);
489
490 if (tobjp->mID == id)
491 {
492 if(object_found == TRUE){
493 //MikeS. adding warning... This happens when removing a linked attachment while sitting on an object..
494 //I think the selection manager needs to be rewritten. BAD.
495 llwarns << "Detected infinite loop #2 in LLSelectMgr::selectionRemoveObject:|" << llendl;
496 break;
497 }
498 object_found = TRUE;
499 }
500 }
501 prevobjp = tobjp;
502 }
503 }
504
505 return object_found;
506}
507
508void LLSelectMgr::deselectObjectAndFamily(LLViewerObject* object, BOOL send_to_sim)
509{
510 // bail if nothing selected or if object wasn't selected in the first place
511 if(!object) return;
512 if(!object->isSelected()) return;
513
514 // Collect all of the objects, and remove them
515 LLDynamicArray<LLViewerObject*> objects;
516 object = (LLViewerObject*)object->getRoot();
517 object->addThisAndAllChildren(objects);
518 remove(objects);
519
520 if (!send_to_sim) return;
521
522 //-----------------------------------------------------------
523 // Inform simulator of deselection
524 //-----------------------------------------------------------
525 LLViewerRegion* regionp = object->getRegion();
526
527 BOOL start_new_message = TRUE;
528 S32 select_count = 0;
529
530 LLMessageSystem* msg = gMessageSystem;
531 for (S32 i = 0; i < objects.count(); i++)
532 {
533 if (start_new_message)
534 {
535 msg->newMessageFast(_PREHASH_ObjectDeselect);
536 msg->nextBlockFast(_PREHASH_AgentData);
537 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
538 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
539 select_count++;
540 start_new_message = FALSE;
541 }
542
543 msg->nextBlockFast(_PREHASH_ObjectData);
544 msg->addU32Fast(_PREHASH_ObjectLocalID, (objects[i])->getLocalID());
545 select_count++;
546
547 if(msg->mCurrentSendTotal >= MTUBYTES || select_count >= MAX_OBJECTS_PER_PACKET)
548 {
549 msg->sendReliable(regionp->getHost() );
550 select_count = 0;
551 start_new_message = TRUE;
552 }
553 }
554
555 if (!start_new_message)
556 {
557 msg->sendReliable(regionp->getHost() );
558 }
559
560 updatePointAt();
561 updateSelectionCenter();
562}
563
564void LLSelectMgr::deselectObjectOnly(LLViewerObject* object, BOOL send_to_sim)
565{
566 // bail if nothing selected or if object wasn't selected in the first place
567 if (!object) return;
568 if (!object->isSelected() ) return;
569
570 if (send_to_sim)
571 {
572 LLViewerRegion* region = object->getRegion();
573 gMessageSystem->newMessageFast(_PREHASH_ObjectDeselect);
574 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
575 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
576 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
577 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
578 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
579 gMessageSystem->sendReliable(region->getHost());
580 }
581
582 // This will refresh dialogs.
583 remove( object );
584
585 updatePointAt();
586 updateSelectionCenter();
587}
588
589
590//-----------------------------------------------------------------------------
591// addAsFamily
592//-----------------------------------------------------------------------------
593
594void LLSelectMgr::addAsFamily(LLDynamicArray<LLViewerObject*>& objects, BOOL add_to_end)
595{
596 S32 count = objects.count();
597 LLViewerObject *objectp = NULL;
598
599 LLSelectNode *nodep = NULL;
600 for (S32 i = 0; i < count; i++)
601 {
602 objectp = objects.get(i);
603
604 // Can't select yourself
605 if (objectp->mID == gAgentID
606 && !gAllowSelectAvatar)
607 {
608 continue;
609 }
610
611 if (!objectp->isSelected())
612 {
613 nodep = new LLSelectNode(objectp, TRUE);
614 if (add_to_end)
615 {
616 mSelectedObjects.addNodeAtEnd(nodep);
617 }
618 else
619 {
620 mSelectedObjects.addNode(nodep);
621 }
622 objectp->setSelected(TRUE);
623
624 if (objectp->getNumTEs() > 0)
625 {
626 nodep->selectAllTEs(TRUE);
627 }
628 else
629 {
630 // object has no faces, so don't mess with faces
631 }
632 }
633 else
634 {
635 // we want this object to be selected for real
636 // so clear transient flag
637 LLSelectNode* select_node = findSelectNode(objectp);
638 if (select_node)
639 {
640 select_node->setTransient(FALSE);
641 }
642 }
643 }
644 saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
645}
646
647//-----------------------------------------------------------------------------
648// addAsIndividual() - a single object, face, etc
649//-----------------------------------------------------------------------------
650void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable)
651{
652 // check to see if object is already in list
653 LLSelectNode *nodep = findSelectNode(objectp);
654
655 // if not in list, add it
656 if (!nodep)
657 {
658 nodep = new LLSelectNode(objectp, TRUE);
659 mSelectedObjects.addNode(nodep);
660 }
661 else
662 {
663 // make this a full-fledged selection
664 nodep->setTransient(FALSE);
665 // Move it to the front of the list
666 mSelectedObjects.removeNode(nodep);
667 mSelectedObjects.addNode(nodep);
668 }
669
670 // Make sure the object is tagged as selected
671 objectp->setSelected( TRUE );
672
673 // And make sure we don't consider it as part of a family
674 nodep->mIndividualSelection = TRUE;
675
676 // Handle face selection
677 if (objectp->getNumTEs() <= 0)
678 {
679 // object has no faces, so don't do anything
680 }
681 else if (face == SELECT_ALL_TES)
682 {
683 nodep->selectAllTEs(TRUE);
684 }
685 else if (0 <= face && face < SELECT_MAX_TES)
686 {
687 nodep->selectTE(face, TRUE);
688 }
689 else
690 {
691 llerrs << "LLSelectMgr::add face " << face << " out-of-range" << llendl;
692 return;
693 }
694
695 saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
696 updateSelectionCenter();
697 dialog_refresh_all();
698}
699
700
701void LLSelectMgr::setHoverObject(LLViewerObject *objectp)
702{
703 // Always blitz hover list when setting
704 mHoverObjects.deleteAllNodes();
705
706 if (!objectp)
707 {
708 return;
709 }
710
711 // Can't select yourself
712 if (objectp->mID == gAgentID)
713 {
714 return;
715 }
716
717 // Can't select land
718 if (objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
719 {
720 return;
721 }
722
723 // Collect all of the objects
724 LLDynamicArray<LLViewerObject*> objects;
725 objectp = objectp->getRootEdit();
726 objectp->addThisAndNonJointChildren(objects);
727
728
729 S32 count = objects.count();
730 LLViewerObject* cur_objectp = NULL;
731 LLSelectNode* nodep = NULL;
732 for(S32 i = 0; i < count; i++)
733 {
734 cur_objectp = objects[i];
735 nodep = new LLSelectNode(cur_objectp, FALSE);
736 mHoverObjects.addNodeAtEnd(nodep);
737 }
738
739 requestObjectPropertiesFamily(objectp);
740}
741
742LLSelectNode *LLSelectMgr::getHoverNode()
743{
744 return getHoverObjects().getFirstRootNode();
745}
746
747void LLSelectMgr::highlightObjectOnly(LLViewerObject* objectp)
748{
749 if (!objectp)
750 {
751 return;
752 }
753
754 if (objectp->getPCode() != LL_PCODE_VOLUME)
755 {
756 return;
757 }
758
759 if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner()) ||
760 (gSavedSettings.getBOOL("SelectMovableOnly") && !objectp->permMove()))
761 {
762 // only select my own objects
763 return;
764 }
765
766 mRectSelectedObjects.insert(objectp);
767}
768
769void LLSelectMgr::highlightObjectAndFamily(LLViewerObject* objectp)
770{
771 if (!objectp)
772 {
773 return;
774 }
775
776 LLViewerObject* root_obj = (LLViewerObject*)objectp->getRoot();
777
778 highlightObjectOnly(root_obj);
779
780 for(U32 i = 0; i < root_obj->mChildList.size(); i++)
781 {
782 highlightObjectOnly(root_obj->mChildList[i]);
783 }
784}
785
786// Note that this ignores the "select owned only" flag
787// It's also more efficient than calling the single-object version over and
788// over.
789void LLSelectMgr::highlightObjectAndFamily(const LLDynamicArray<LLViewerObject*>& list)
790{
791 S32 i;
792 S32 count = list.count();
793
794 for (i = 0; i < count; i++)
795 {
796 LLViewerObject* object = list.get(i);
797
798 if (!object) continue;
799 if (object->getPCode() != LL_PCODE_VOLUME) continue;
800
801 LLViewerObject* root = (LLViewerObject*)object->getRoot();
802 mRectSelectedObjects.insert(root);
803
804 S32 j;
805 S32 child_count = root->mChildList.size();
806 for (j = 0; j < child_count; j++)
807 {
808 LLViewerObject* child = root->mChildList[j];
809 mRectSelectedObjects.insert(child);
810 }
811 }
812}
813
814void LLSelectMgr::unhighlightObjectOnly(LLViewerObject* objectp)
815{
816 if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
817 {
818 return;
819 }
820
821 mRectSelectedObjects.erase(objectp);
822}
823
824void LLSelectMgr::unhighlightObjectAndFamily(LLViewerObject* objectp)
825{
826 if (!objectp)
827 {
828 return;
829 }
830
831 LLViewerObject* root_obj = (LLViewerObject*)objectp->getRoot();
832
833 unhighlightObjectOnly(root_obj);
834
835 for(U32 i = 0; i < root_obj->mChildList.size(); i++)
836 {
837 unhighlightObjectOnly(root_obj->mChildList[i]);
838 }
839}
840
841
842void LLSelectMgr::unhighlightAll()
843{
844 mRectSelectedObjects.clear();
845 mHighlightedObjects.deleteAllNodes();
846}
847
848void LLSelectMgr::selectHighlightedObjects()
849{
850 if (!mHighlightedObjects.getNumNodes())
851 {
852 return;
853 }
854
855 LLSelectNode *nodep;
856 for (nodep = mHighlightedObjects.getFirstNode();
857 nodep;
858 nodep = mHighlightedObjects.getNextNode())
859 {
860 LLViewerObject* objectp = nodep->getObject();
861
862 if (!canSelectObject(objectp))
863 {
864 continue;
865 }
866
867 // already selected
868 if (objectp->isSelected())
869 {
870 continue;
871 }
872
873 LLSelectNode* new_nodep = new LLSelectNode(*nodep);
874 mSelectedObjects.addNode(new_nodep);
875
876 // flag this object as selected
877 objectp->setSelected(TRUE);
878
879 mSelectType = getSelectTypeForObject(objectp);
880
881 // request properties on root objects
882 if (objectp->isRootEdit())
883 {
884 requestObjectPropertiesFamily(objectp);
885 }
886 }
887
888 // pack up messages to let sim know these objects are selected
889 sendSelect();
890 unhighlightAll();
891 updateSelectionCenter();
892 saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
893 updatePointAt();
894
895 if (getObjectCount())
896 {
897 gEditMenuHandler = this;
898 }
899}
900
901void LLSelectMgr::deselectHighlightedObjects()
902{
903 BOOL select_linked_set = gSavedSettings.getBOOL("SelectLinkedSet");
904 for (std::set<LLPointer<LLViewerObject> >::iterator iter = mRectSelectedObjects.begin();
905 iter != mRectSelectedObjects.end(); iter++)
906 {
907 LLViewerObject *objectp = *iter;
908 if (!select_linked_set)
909 {
910 deselectObjectOnly(objectp);
911 }
912 else
913 {
914 LLViewerObject* root_object = (LLViewerObject*)objectp->getRoot();
915 if (root_object->isSelected())
916 {
917 deselectObjectAndFamily(root_object);
918 }
919 }
920 }
921
922 unhighlightAll();
923}
924
925void LLSelectMgr::addGridObject(LLViewerObject* objectp)
926{
927 LLSelectNode* nodep = new LLSelectNode(objectp, FALSE);
928 mGridObjects.addNodeAtEnd(nodep);
929 for (U32 i = 0; i < objectp->mChildList.size(); i++)
930 {
931 nodep = new LLSelectNode(objectp->mChildList[i], FALSE);
932 mGridObjects.addNodeAtEnd(nodep);
933 }
934}
935
936void LLSelectMgr::clearGridObjects()
937{
938 mGridObjects.deleteAllNodes();
939}
940
941void LLSelectMgr::setGridMode(EGridMode mode)
942{
943 mGridMode = mode;
944 gSavedSettings.setS32("GridMode", mode);
945 updateSelectionCenter();
946 mGridValid = FALSE;
947}
948
949void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale)
950{
951 LLSelectNode* grid_node = mGridObjects.getFirstNode();
952 LLViewerObject* grid_object = mGridObjects.getFirstObject();
953 // *TODO: get to work with multiple grid objects
954 if (grid_node && grid_node->getObject()->isDead())
955 {
956 mGridObjects.removeNode(grid_node);
957 grid_object = NULL;
958 }
959
960 if (mGridMode == GRID_MODE_LOCAL && gSelectMgr->getObjectCount())
961 {
962 LLBBox bbox = mSavedSelectionBBox;
963 mGridOrigin = mSavedSelectionBBox.getCenterAgent();
964 mGridRotation = mSavedSelectionBBox.getRotation();
965 mGridScale = mSavedSelectionBBox.getExtentLocal() * 0.5f;
966 }
967 else if (mGridMode == GRID_MODE_REF_OBJECT && grid_object && grid_object->mDrawable.notNull())
968 {
969 mGridRotation = grid_object->getRenderRotation();
970 LLVector3 first_grid_obj_pos = grid_object->getRenderPosition();
971
972 LLVector3 min_extents(F32_MAX, F32_MAX, F32_MAX);
973 LLVector3 max_extents(F32_MIN, F32_MIN, F32_MIN);
974 BOOL grid_changed = FALSE;
975 LLSelectNode* grid_nodep;
976 for (grid_nodep = mGridObjects.getFirstNode();
977 grid_nodep;
978 grid_nodep = mGridObjects.getNextNode())
979 {
980 grid_object = grid_nodep->getObject();
981
982 LLVector3 local_min_extents(F32_MAX, F32_MAX, F32_MAX);
983 LLVector3 local_max_extents(F32_MIN, F32_MIN, F32_MIN);
984
985 // *FIX: silhouette flag is insufficient as it gets
986 // cleared by view update.
987 if (!mGridValid ||
988 grid_object->isChanged(LLXform::SILHOUETTE)
989 || (grid_object->getParent() && grid_object->getParent()->isChanged(LLXform::SILHOUETTE)))
990 {
991 getSilhouetteExtents(grid_nodep, mGridRotation, local_min_extents, local_max_extents);
992 grid_changed = TRUE;
993 LLVector3 object_offset = (grid_object->getRenderPosition() - first_grid_obj_pos) * ~mGridRotation;
994 local_min_extents += object_offset;
995 local_max_extents += object_offset;
996 }
997 min_extents.mV[VX] = llmin(min_extents.mV[VX], local_min_extents.mV[VX]);
998 min_extents.mV[VY] = llmin(min_extents.mV[VY], local_min_extents.mV[VY]);
999 min_extents.mV[VZ] = llmin(min_extents.mV[VZ], local_min_extents.mV[VZ]);
1000 max_extents.mV[VX] = llmax(max_extents.mV[VX], local_max_extents.mV[VX]);
1001 max_extents.mV[VY] = llmax(max_extents.mV[VY], local_max_extents.mV[VY]);
1002 max_extents.mV[VZ] = llmax(max_extents.mV[VZ], local_max_extents.mV[VZ]);
1003 }
1004 if (grid_changed)
1005 {
1006 mGridOrigin = lerp(min_extents, max_extents, 0.5f);
1007 mGridOrigin = mGridOrigin * ~mGridRotation;
1008 mGridOrigin += first_grid_obj_pos;
1009 mGridScale = (max_extents - min_extents) * 0.5f;
1010 }
1011 }
1012 else // GRID_MODE_WORLD or just plain default
1013 {
1014 LLViewerObject* first_object = gSelectMgr->getFirstRootObject();
1015 if (!first_object)
1016 {
1017 first_object = gSelectMgr->getFirstObject();
1018 }
1019
1020 mGridOrigin.clearVec();
1021 mGridRotation.loadIdentity();
1022
1023 mSelectType = getSelectTypeForObject( first_object );
1024
1025 switch (mSelectType)
1026 {
1027 case SELECT_TYPE_ATTACHMENT:
1028 if (first_object)
1029 {
1030 // this means this object *has* to be an attachment
1031 LLXform* attachment_point_xform = first_object->getRootEdit()->mDrawable->mXform.getParent();
1032 mGridOrigin = attachment_point_xform->getWorldPosition();
1033 mGridRotation = attachment_point_xform->getWorldRotation();
1034 mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution");
1035 }
1036 break;
1037 case SELECT_TYPE_HUD:
1038 // use HUD-scaled grid
1039 mGridScale = LLVector3(0.25f, 0.25f, 0.25f);
1040 break;
1041 case SELECT_TYPE_WORLD:
1042 mGridScale = LLVector3(1.f, 1.f, 1.f) * gSavedSettings.getF32("GridResolution");
1043 break;
1044 }
1045 }
1046 llassert(mGridOrigin.isFinite());
1047
1048 origin = mGridOrigin;
1049 rotation = mGridRotation;
1050 scale = mGridScale;
1051 mGridValid = TRUE;
1052}
1053
1054
1055
1056LLSelectNode* LLSelectMgr::findSelectNode(LLViewerObject *object)
1057{
1058 return mSelectedObjects.findNode(object);
1059}
1060
1061//-----------------------------------------------------------------------------
1062// contains()
1063//-----------------------------------------------------------------------------
1064BOOL LLSelectMgr::contains(LLViewerObject* object)
1065{
1066 return mSelectedObjects.findNode(object) != NULL;
1067}
1068
1069
1070//-----------------------------------------------------------------------------
1071// contains()
1072//-----------------------------------------------------------------------------
1073BOOL LLSelectMgr::contains(LLViewerObject* object, S32 te)
1074{
1075 LLSelectNode *nodep;
1076 if (te == SELECT_ALL_TES)
1077 {
1078 // ...all faces
1079 for (nodep = mSelectedObjects.getFirstNode(); nodep; nodep = mSelectedObjects.getNextNode() )
1080 {
1081 if (nodep->getObject() == object)
1082 {
1083 BOOL all_selected = TRUE;
1084 for (S32 i = 0; i < SELECT_MAX_TES; i++)
1085 {
1086 all_selected = all_selected && nodep->isTESelected(i);
1087 }
1088 return all_selected;
1089 }
1090 }
1091 return FALSE;
1092 }
1093 else
1094 {
1095 // ...one face
1096 for (nodep = mSelectedObjects.getFirstNode(); nodep; nodep = mSelectedObjects.getNextNode() )
1097 {
1098 if (nodep->getObject() == object && nodep->isTESelected(te))
1099 {
1100 return TRUE;
1101 }
1102 }
1103 return FALSE;
1104 }
1105}
1106
1107//-----------------------------------------------------------------------------
1108// remove() - an array of objects
1109//-----------------------------------------------------------------------------
1110
1111void LLSelectMgr::remove(LLDynamicArray<LLViewerObject*>& objects)
1112{
1113 S32 count = objects.count();
1114 LLViewerObject *objectp = NULL;
1115 LLSelectNode *nodep = NULL;
1116 for(S32 i = 0; i < count; i++)
1117 {
1118 objectp = objects.get(i);
1119 for(nodep = mSelectedObjects.getFirstNode();
1120 nodep != NULL;
1121 nodep = mSelectedObjects.getNextNode())
1122 {
1123 if(nodep->getObject() == objectp)
1124 {
1125 objectp->setSelected(FALSE);
1126 mSelectedObjects.removeNode(nodep);
1127 break;
1128 }
1129 }
1130 }
1131 updateSelectionCenter();
1132 dialog_refresh_all();
1133}
1134
1135
1136//-----------------------------------------------------------------------------
1137// remove() - a single object
1138//-----------------------------------------------------------------------------
1139void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, BOOL undoable)
1140{
1141 // check if object already in list
1142 // *FIX: can we just check isSelected()?
1143 LLSelectNode *nodep = findSelectNode(objectp);
1144
1145 if (!nodep)
1146 {
1147 return;
1148 }
1149
1150
1151 // if face = all, remove object from list
1152 if (objectp->getNumTEs() <= 0)
1153 {
1154 // object doesn't have faces, so blow it away
1155 mSelectedObjects.removeNode(nodep);
1156 objectp->setSelected( FALSE );
1157 }
1158 else if (te == SELECT_ALL_TES)
1159 {
1160 mSelectedObjects.removeNode(nodep);
1161 objectp->setSelected( FALSE );
1162 }
1163 else if (0 <= te && te < SELECT_MAX_TES)
1164 {
1165 // ...valid face, check to see if it was on
1166 if (nodep->isTESelected(te))
1167 {
1168 nodep->selectTE(te, FALSE);
1169 }
1170 else
1171 {
1172 llerrs << "LLSelectMgr::remove - tried to remove TE " << te << " that wasn't selected" << llendl;
1173 return;
1174 }
1175
1176 // ...check to see if this operation turned off all faces
1177 BOOL found = FALSE;
1178 for (S32 i = 0; i < nodep->getObject()->getNumTEs(); i++)
1179 {
1180 found = found || nodep->isTESelected(i);
1181 }
1182
1183 // ...all faces now turned off, so remove
1184 if (!found)
1185 {
1186 mSelectedObjects.removeNode(nodep);
1187 objectp->setSelected( FALSE );
1188
1189 // BUG: Doesn't update simulator that object is gone.
1190 }
1191 }
1192 else
1193 {
1194 // ...out of range face
1195 llerrs << "LLSelectMgr::remove - TE " << te << " out of range" << llendl;
1196 }
1197
1198 updateSelectionCenter();
1199 dialog_refresh_all();
1200}
1201
1202
1203//-----------------------------------------------------------------------------
1204// removeAll()
1205//-----------------------------------------------------------------------------
1206void LLSelectMgr::removeAll()
1207{
1208 LLViewerObject *objectp;
1209 for (objectp = mSelectedObjects.getFirstObject(); objectp; objectp = mSelectedObjects.getNextObject() )
1210 {
1211 objectp->setSelected( FALSE );
1212 }
1213
1214 mSelectedObjects.deleteAllNodes();
1215
1216 updateSelectionCenter();
1217 dialog_refresh_all();
1218}
1219
1220//-----------------------------------------------------------------------------
1221// promoteSelectionToRoot()
1222//-----------------------------------------------------------------------------
1223void LLSelectMgr::promoteSelectionToRoot()
1224{
1225 std::set<LLViewerObject*> selection_set;
1226
1227 BOOL selection_changed = FALSE;
1228
1229 LLSelectNode* nodep;
1230 LLViewerObject *objectp;
1231 for (nodep = mSelectedObjects.getFirstNode();
1232 nodep;
1233 nodep = mSelectedObjects.getNextNode() )
1234 {
1235 if (nodep->mIndividualSelection)
1236 {
1237 selection_changed = TRUE;
1238 }
1239
1240 objectp = nodep->getObject();
1241 LLViewerObject* parentp = objectp;
1242 while(parentp->getParent() && !(parentp->isRootEdit() || parentp->isJointChild()))
1243 {
1244 parentp = (LLViewerObject*)parentp->getParent();
1245 }
1246
1247 selection_set.insert(parentp);
1248 }
1249
1250 if (selection_changed)
1251 {
1252 deselectAll();
1253
1254 std::set<LLViewerObject*>::iterator set_iter;
1255 for (set_iter = selection_set.begin(); set_iter != selection_set.end(); ++set_iter)
1256 {
1257 selectObjectAndFamily(*set_iter);
1258 }
1259 }
1260}
1261
1262//-----------------------------------------------------------------------------
1263// demoteSelectionToIndividuals()
1264//-----------------------------------------------------------------------------
1265void LLSelectMgr::demoteSelectionToIndividuals()
1266{
1267 LLDynamicArray<LLViewerObject*> objects;
1268
1269 for (LLViewerObject* root_objectp = mSelectedObjects.getFirstRootObject();
1270 root_objectp;
1271 root_objectp = mSelectedObjects.getNextRootObject())
1272 {
1273 root_objectp->addThisAndNonJointChildren(objects);
1274 }
1275
1276 if (objects.getLength())
1277 {
1278 deselectAll();
1279 for(S32 i = 0; i < objects.count(); i++)
1280 {
1281 selectObjectOnly(objects[i]);
1282 }
1283 }
1284}
1285
1286//-----------------------------------------------------------------------------
1287// getObjectCount()
1288//-----------------------------------------------------------------------------
1289S32 LLSelectMgr::getObjectCount()
1290{
1291 return mSelectedObjects.getNumNodes();
1292}
1293
1294
1295//-----------------------------------------------------------------------------
1296// getTECount()
1297//-----------------------------------------------------------------------------
1298S32 LLSelectMgr::getTECount()
1299{
1300 S32 count = 0;
1301
1302 LLSelectNode* nodep;
1303 for (nodep = mSelectedObjects.getFirstNode(); nodep; nodep = mSelectedObjects.getNextNode() )
1304 {
1305 if (nodep->getObject())
1306 {
1307 S32 num_tes = nodep->getObject()->getNumTEs();
1308 for (S32 te = 0; te < num_tes; te++)
1309 {
1310 if (nodep->isTESelected(te))
1311 {
1312 count++;
1313 }
1314 }
1315 }
1316 }
1317
1318 return count;
1319}
1320
1321//-----------------------------------------------------------------------------
1322// getRootObjectCount()
1323//-----------------------------------------------------------------------------
1324S32 LLSelectMgr::getRootObjectCount()
1325{
1326 LLSelectNode *nodep;
1327
1328 S32 count = 0;
1329 for(nodep = mSelectedObjects.getFirstRootNode(); nodep; nodep = mSelectedObjects.getNextRootNode())
1330 {
1331 ++count;
1332 }
1333 return count;
1334}
1335
1336
1337//-----------------------------------------------------------------------------
1338// dump()
1339//-----------------------------------------------------------------------------
1340void LLSelectMgr::dump()
1341{
1342 llinfos << "Selection Manager: " << mSelectedObjects.getNumNodes() << " items" << llendl;
1343
1344 llinfos << "TE mode " << mTEMode << llendl;
1345
1346 S32 i = 0;
1347
1348 LLViewerObject *objectp;
1349 for (objectp = mSelectedObjects.getFirstObject();
1350 objectp;
1351 objectp = mSelectedObjects.getNextObject())
1352 {
1353 llinfos << "Object " << i << " type " << LLPrimitive::pCodeToString(objectp->getPCode()) << llendl;
1354 llinfos << " hasLSL " << objectp->flagScripted() << llendl;
1355 llinfos << " hasTouch " << objectp->flagHandleTouch() << llendl;
1356 llinfos << " hasMoney " << objectp->flagTakesMoney() << llendl;
1357 llinfos << " getposition " << objectp->getPosition() << llendl;
1358 llinfos << " getpositionAgent " << objectp->getPositionAgent() << llendl;
1359 llinfos << " getpositionRegion " << objectp->getPositionRegion() << llendl;
1360 llinfos << " getpositionGlobal " << objectp->getPositionGlobal() << llendl;
1361 LLDrawable* drawablep = objectp->mDrawable;
1362 llinfos << " " << (drawablep&& drawablep->isVisible() ? "visible" : "invisible") << llendl;
1363 llinfos << " " << (drawablep&& drawablep->isState(LLDrawable::FORCE_INVISIBLE) ? "force_invisible" : "") << llendl;
1364 i++;
1365 }
1366
1367 // Face iterator
1368 S32 te;
1369 for (mSelectedObjects.getFirstTE(&objectp, &te);
1370 objectp;
1371 mSelectedObjects.getNextTE(&objectp, &te))
1372 {
1373 llinfos << "Object " << objectp << " te " << te << llendl;
1374 }
1375
1376 llinfos << mHighlightedObjects.getNumNodes() << " objects currently highlighted." << llendl;
1377
1378 llinfos << "Center global " << mSelectionCenterGlobal << llendl;
1379}
1380
1381//-----------------------------------------------------------------------------
1382// cleanup()
1383//-----------------------------------------------------------------------------
1384void LLSelectMgr::cleanup()
1385{
1386 mSilhouetteImagep = NULL;
1387}
1388
1389
1390//---------------------------------------------------------------------------
1391// Manipulate properties of selected objects
1392//---------------------------------------------------------------------------
1393
1394//-----------------------------------------------------------------------------
1395// selectionSetImage()
1396//-----------------------------------------------------------------------------
1397// *TODO: re-arch texture applying out of lltooldraganddrop
1398void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
1399{
1400 // First for (no copy) textures and multiple object selection
1401 LLViewerInventoryItem* item = gInventory.getItem(imageid);
1402
1403 if(item
1404 && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
1405 && (mSelectedObjects.getNumNodes() > 1) )
1406 {
1407 llwarns << "Attempted to apply no-copy texture to multiple objects"
1408 << llendl;
1409 return;
1410 }
1411
1412 LLViewerObject* objectp;
1413 S32 te;
1414
1415 // Apply the texture to each side
1416 for (mSelectedObjects.getFirstTE(&objectp, &te); objectp; mSelectedObjects.getNextTE(&objectp, &te))
1417 {
1418
1419 if (item)
1420 {
1421 LLToolDragAndDrop::dropTextureOneFace(objectp,te,item,LLToolDragAndDrop::SOURCE_AGENT,LLUUID::null);
1422
1423 // HACK! HACK! ARG!
1424 // *TODO: Replace mSelectedObjects with a REAL container class!
1425 LLViewerObject* tmp_object;
1426 S32 tmp_te;
1427 mSelectedObjects.getCurrentTE(&tmp_object,&tmp_te);
1428 if ((tmp_object != objectp) || (tmp_te != te) )
1429 {
1430 //AAARG someone has moved our list around!
1431 mSelectedObjects.getFirstTE(&tmp_object, &tmp_te);
1432 while ((tmp_object != objectp) || (tmp_te != te))
1433 {
1434 mSelectedObjects.getNextTE(&tmp_object, &tmp_te);
1435 }
1436 }
1437 }
1438 else
1439 {
1440 // Texture picker defaults aren't inventory items
1441 // * Don't need to worry about permissions for them
1442 // * Can just apply the texture and be done with it.
1443 objectp->setTEImage(te, gImageList.getImage(imageid));
1444 objectp->sendTEUpdate();
1445 }
1446 }
1447
1448 // 1 particle effect per object
1449 if (mSelectType != SELECT_TYPE_HUD)
1450 {
1451 for (objectp = mSelectedObjects.getFirstObject(); objectp; objectp = mSelectedObjects.getNextObject())
1452 {
1453 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
1454 effectp->setSourceObject(gAgent.getAvatarObject());
1455 effectp->setTargetObject(objectp);
1456 effectp->setDuration(LL_HUD_DUR_SHORT);
1457 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
1458 }
1459 }
1460}
1461
1462//-----------------------------------------------------------------------------
1463// selectionSetColor()
1464//-----------------------------------------------------------------------------
1465void LLSelectMgr::selectionSetColor(const LLColor4 &color)
1466{
1467 LLViewerObject* object;
1468 S32 te;
1469 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1470 {
1471 if (object->permModify())
1472 {
1473 // update viewer side color in anticipation of update from simulator
1474 object->setTEColor(te, color);
1475 }
1476 }
1477
1478 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1479 {
1480 if (object->permModify())
1481 {
1482 object->sendTEUpdate();
1483 }
1484 }
1485}
1486
1487//-----------------------------------------------------------------------------
1488// selectionSetColorOnly()
1489//-----------------------------------------------------------------------------
1490void LLSelectMgr::selectionSetColorOnly(const LLColor4 &color)
1491{
1492 LLViewerObject* object;
1493 LLColor4 new_color = color;
1494 S32 te;
1495 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1496 {
1497 if (object->permModify())
1498 {
1499 LLColor4 prev_color = object->getTE(te)->getColor();
1500 new_color.mV[VALPHA] = prev_color.mV[VALPHA];
1501 // update viewer side color in anticipation of update from simulator
1502 object->setTEColor(te, new_color);
1503 }
1504 }
1505
1506 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1507 {
1508 if (object->permModify())
1509 {
1510 object->sendTEUpdate();
1511 }
1512 }
1513}
1514
1515//-----------------------------------------------------------------------------
1516// selectionSetAlphaOnly()
1517//-----------------------------------------------------------------------------
1518void LLSelectMgr::selectionSetAlphaOnly(const F32 alpha)
1519{
1520 LLViewerObject* object;
1521 S32 te;
1522 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1523 {
1524 if (object->permModify())
1525 {
1526 LLColor4 prev_color = object->getTE(te)->getColor();
1527 prev_color.mV[VALPHA] = alpha;
1528 // update viewer side color in anticipation of update from simulator
1529 object->setTEColor(te, prev_color);
1530 }
1531 }
1532
1533 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1534 {
1535 if (object->permModify())
1536 {
1537 object->sendTEUpdate();
1538 }
1539 }
1540}
1541
1542void LLSelectMgr::selectionRevertColors()
1543{
1544 LLViewerObject* object;
1545 S32 te;
1546
1547 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1548 {
1549 if (object->permModify())
1550 {
1551 LLSelectNode* nodep = mSelectedObjects.findNode(object);
1552 if (nodep && te < (S32)nodep->mSavedColors.size())
1553 {
1554 LLColor4 color = nodep->mSavedColors[te];
1555 // update viewer side color in anticipation of update from simulator
1556 object->setTEColor(te, color);
1557 }
1558 }
1559 }
1560
1561 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1562 {
1563 if (object->permModify())
1564 {
1565 object->sendTEUpdate();
1566 }
1567 }
1568}
1569
1570BOOL LLSelectMgr::selectionRevertTextures()
1571{
1572 LLViewerObject* object;
1573 S32 te;
1574
1575 BOOL revert_successful = TRUE;
1576 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1577 {
1578 if (object->permModify())
1579 {
1580 LLSelectNode* nodep = mSelectedObjects.findNode(object);
1581 if (nodep && te < (S32)nodep->mSavedTextures.size())
1582 {
1583 LLUUID id = nodep->mSavedTextures[te];
1584 // update textures on viewer side
1585 if (id.isNull())
1586 {
1587 // this was probably a no-copy texture, leave image as-is
1588 revert_successful = FALSE;
1589 }
1590 else
1591 {
1592 object->setTEImage(te, gImageList.getImage(id));
1593 }
1594 }
1595 }
1596 }
1597
1598 // propagate texture changes to server
1599 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1600 {
1601 if (object->permModify())
1602 {
1603 object->sendTEUpdate();
1604 }
1605 }
1606
1607 return revert_successful;
1608}
1609
1610void LLSelectMgr::selectionSetBumpmap(U8 bumpmap)
1611{
1612 LLViewerObject* object;
1613 S32 te;
1614 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1615 {
1616 if (object->permModify())
1617 {
1618 // update viewer side color in anticipation of update from simulator
1619 object->setTEBumpmap(te, bumpmap);
1620 }
1621 }
1622
1623 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1624 {
1625 if (object->permModify())
1626 {
1627 object->sendTEUpdate();
1628 }
1629 }
1630}
1631
1632void LLSelectMgr::selectionSetTexGen(U8 texgen)
1633{
1634 LLViewerObject* object;
1635 S32 te;
1636 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1637 {
1638 if (object->permModify())
1639 {
1640 // update viewer side color in anticipation of update from simulator
1641 object->setTETexGen(te, texgen);
1642 }
1643 }
1644
1645 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1646 {
1647 if (object->permModify())
1648 {
1649 object->sendTEUpdate();
1650 }
1651 }
1652}
1653
1654
1655void LLSelectMgr::selectionSetShiny(U8 shiny)
1656{
1657 LLViewerObject* object;
1658 S32 te;
1659 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1660 {
1661 if (object->permModify())
1662 {
1663 // update viewer side color in anticipation of update from simulator
1664 object->setTEShiny(te, shiny);
1665 }
1666 }
1667
1668 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1669 {
1670 if (object->permModify())
1671 {
1672 object->sendTEUpdate();
1673 }
1674 }
1675}
1676
1677void LLSelectMgr::selectionSetFullbright(U8 fullbright)
1678{
1679 LLViewerObject* object;
1680 S32 te;
1681 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1682 {
1683 if (object->permModify())
1684 {
1685 // update viewer side color in anticipation of update from simulator
1686 object->setTEFullbright(te, fullbright);
1687 }
1688 }
1689
1690 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1691 {
1692 if (object->permModify())
1693 {
1694 object->sendTEUpdate();
1695 if (fullbright)
1696 {
1697 U8 material = object->getMaterial();
1698 U8 mcode = material & LL_MCODE_MASK;
1699 if (mcode == LL_MCODE_LIGHT)
1700 {
1701 mcode = LL_MCODE_GLASS;
1702 material = (material & ~LL_MCODE_MASK) | mcode;
1703 object->setMaterial(material);
1704 object->sendMaterialUpdate();
1705 }
1706 }
1707 }
1708 }
1709}
1710
1711void LLSelectMgr::selectionSetMediaTypeAndURL(U8 media_type, const std::string& media_url)
1712{
1713 LLViewerObject* object;
1714 S32 te;
1715 U8 media_flags = LLTextureEntry::MF_NONE;
1716 if (media_type == LLViewerObject::MEDIA_TYPE_WEB_PAGE)
1717 {
1718 media_flags = LLTextureEntry::MF_WEB_PAGE;
1719 }
1720
1721 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te) )
1722 {
1723 if (object->permModify())
1724 {
1725 // update viewer side color in anticipation of update from simulator
1726 object->setTEMediaFlags(te, media_flags);
1727 }
1728 }
1729
1730 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
1731 {
1732 if (object->permModify())
1733 {
1734 // JAMESDEBUG TODO set object media type
1735 object->setMediaType(media_type);
1736 object->setMediaURL(media_url);
1737
1738 object->sendTEUpdate();
1739 }
1740 }
1741}
1742
1743
1744
1745//-----------------------------------------------------------------------------
1746// findObjectPermissions()
1747//-----------------------------------------------------------------------------
1748LLPermissions* LLSelectMgr::findObjectPermissions(const LLViewerObject* object)
1749{
1750 LLSelectNode* nodep;
1751
1752 for (nodep = mSelectedObjects.getFirstNode(); nodep; nodep = mSelectedObjects.getNextNode() )
1753 {
1754 if((nodep->getObject() == object) && nodep->mValid)
1755 {
1756 return nodep->mPermissions;
1757 }
1758 }
1759
1760 return NULL;
1761}
1762
1763
1764//-----------------------------------------------------------------------------
1765// selectionGetTexUUID()
1766//-----------------------------------------------------------------------------
1767BOOL LLSelectMgr::selectionGetTexUUID(LLUUID& id)
1768{
1769 LLViewerObject* first_objectp;
1770 S32 first_te;
1771 mSelectedObjects.getPrimaryTE(&first_objectp, &first_te);
1772
1773 // nothing selected
1774 if (!first_objectp)
1775 {
1776 return FALSE;
1777 }
1778
1779 LLViewerImage* first_imagep = first_objectp->getTEImage(first_te);
1780
1781 if (!first_imagep)
1782 {
1783 return FALSE;
1784 }
1785
1786 BOOL identical = TRUE;
1787 LLViewerObject *objectp;
1788 S32 te;
1789 for (mSelectedObjects.getFirstTE(&objectp, &te); objectp; mSelectedObjects.getNextTE(&objectp, &te) )
1790 {
1791 if (objectp->getTEImage(te) != first_imagep)
1792 {
1793 identical = FALSE;
1794 break;
1795 }
1796 }
1797
1798 id = first_imagep->getID();
1799 return identical;
1800}
1801
1802//-----------------------------------------------------------------------------
1803// selectionGetColor()
1804//-----------------------------------------------------------------------------
1805BOOL LLSelectMgr::selectionGetColor(LLColor4 &color)
1806{
1807 LLViewerObject* first_object;
1808 S32 first_te;
1809 mSelectedObjects.getPrimaryTE(&first_object, &first_te);
1810
1811 // nothing selected
1812 if (!first_object)
1813 {
1814 return FALSE;
1815 }
1816
1817 LLColor4 first_color;
1818 if (!first_object->getTE(first_te))
1819 {
1820 return FALSE;
1821 }
1822 else
1823 {
1824 first_color = first_object->getTE(first_te)->getColor();
1825 }
1826
1827 BOOL identical = TRUE;
1828 LLViewerObject* object;
1829 S32 te;
1830 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te))
1831 {
1832 if (!object->getTE(te) || (object->getTE(te)->getColor() != first_color))
1833 {
1834 identical = FALSE;
1835 break;
1836 }
1837 }
1838
1839 color = first_color;
1840 return identical;
1841}
1842
1843
1844//-----------------------------------------------------------------------------
1845// selectionGetBumpmap()
1846//-----------------------------------------------------------------------------
1847BOOL LLSelectMgr::selectionGetBumpmap(U8 *bumpmap)
1848{
1849 LLViewerObject* first_object;
1850 S32 first_te;
1851 mSelectedObjects.getPrimaryTE(&first_object, &first_te);
1852
1853 // nothing selected
1854 if (!first_object)
1855 {
1856 return FALSE;
1857 }
1858
1859 U8 first_value;
1860 if (!first_object->getTE(first_te))
1861 {
1862 return FALSE;
1863 }
1864 else
1865 {
1866 first_value = first_object->getTE(first_te)->getBumpmap();
1867 }
1868
1869 BOOL identical = TRUE;
1870 LLViewerObject* object;
1871 S32 te;
1872 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te))
1873 {
1874 if (!object->getTE(te) || (object->getTE(te)->getBumpmap() != first_value))
1875 {
1876 identical = FALSE;
1877 break;
1878 }
1879 }
1880
1881 *bumpmap = first_value;
1882 return identical;
1883}
1884
1885//-----------------------------------------------------------------------------
1886// selectionGetShiny()
1887//-----------------------------------------------------------------------------
1888BOOL LLSelectMgr::selectionGetShiny(U8 *shiny)
1889{
1890 LLViewerObject* first_object;
1891 S32 first_te;
1892 mSelectedObjects.getPrimaryTE(&first_object, &first_te);
1893
1894 // nothing selected
1895 if (!first_object)
1896 {
1897 return FALSE;
1898 }
1899
1900 U8 first_value;
1901 if (!first_object->getTE(first_te))
1902 {
1903 return FALSE;
1904 }
1905 else
1906 {
1907 first_value = first_object->getTE(first_te)->getShiny();
1908 }
1909
1910 BOOL identical = TRUE;
1911 LLViewerObject* object;
1912 S32 te;
1913 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te))
1914 {
1915 if (!object->getTE(te) || (object->getTE(te)->getShiny() != first_value))
1916 {
1917 identical = FALSE;
1918 break;
1919 }
1920 }
1921
1922 *shiny = first_value;
1923 return identical;
1924}
1925
1926//-----------------------------------------------------------------------------
1927// selectionGetFullbright()
1928//-----------------------------------------------------------------------------
1929BOOL LLSelectMgr::selectionGetFullbright(U8 *fullbright)
1930{
1931 LLViewerObject* first_object;
1932 S32 first_te;
1933 mSelectedObjects.getPrimaryTE(&first_object, &first_te);
1934
1935 // nothing selected
1936 if (!first_object)
1937 {
1938 return FALSE;
1939 }
1940
1941 U8 first_value;
1942 if (!first_object->getTE(first_te))
1943 {
1944 return FALSE;
1945 }
1946 else
1947 {
1948 first_value = first_object->getTE(first_te)->getFullbright();
1949 }
1950
1951 BOOL identical = TRUE;
1952 LLViewerObject* object;
1953 S32 te;
1954 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te))
1955 {
1956 if (!object->getTE(te) || (object->getTE(te)->getFullbright() != first_value))
1957 {
1958 identical = FALSE;
1959 break;
1960 }
1961 }
1962
1963 *fullbright = first_value;
1964 return identical;
1965}
1966
1967// JAMESDEBUG TODO make this return mediatype off viewer object
1968bool LLSelectMgr::selectionGetMediaType(U8 *media_type)
1969{
1970 LLViewerObject* first_object;
1971 S32 first_te;
1972 mSelectedObjects.getPrimaryTE(&first_object, &first_te);
1973
1974 // nothing selected
1975 if (!first_object)
1976 {
1977 return false;
1978 }
1979
1980 U8 first_value;
1981 if (!first_object->getTE(first_te))
1982 {
1983 return false;
1984 }
1985 else
1986 {
1987 first_value = first_object->getTE(first_te)->getMediaFlags();
1988 }
1989
1990 bool identical = true;
1991 LLViewerObject* object;
1992 S32 te;
1993 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te))
1994 {
1995 if (!object->getTE(te) || (object->getTE(te)->getMediaFlags() != first_value))
1996 {
1997 identical = false;
1998 break;
1999 }
2000 }
2001
2002 *media_type = first_value;
2003 return identical;
2004}
2005
2006
2007
2008//-----------------------------------------------------------------------------
2009// selectionSetMaterial()
2010//-----------------------------------------------------------------------------
2011void LLSelectMgr::selectionSetMaterial(U8 material)
2012{
2013 LLViewerObject* object;
2014 for (object = mSelectedObjects.getFirstObject(); object != NULL; object = mSelectedObjects.getNextObject() )
2015 {
2016 if (object->permModify())
2017 {
2018 U8 cur_material = object->getMaterial();
2019 material |= (cur_material & ~LL_MCODE_MASK);
2020 object->setMaterial(material);
2021 object->sendMaterialUpdate();
2022 }
2023 }
2024}
2025
2026// True if all selected objects have this PCode
2027BOOL LLSelectMgr::selectionAllPCode(LLPCode code)
2028{
2029 LLViewerObject *object;
2030 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
2031 {
2032 if (object->getPCode() != code)
2033 {
2034 return FALSE;
2035 }
2036 }
2037 return TRUE;
2038}
2039
2040//-----------------------------------------------------------------------------
2041// selectionGetMaterial()
2042//-----------------------------------------------------------------------------
2043BOOL LLSelectMgr::selectionGetMaterial(U8 *out_material)
2044{
2045 LLViewerObject *object = mSelectedObjects.getFirstObject();
2046 if (!object) return FALSE;
2047
2048 U8 material = object->getMaterial();
2049
2050 BOOL identical = TRUE;
2051 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
2052 {
2053 if ( material != object->getMaterial())
2054 {
2055 identical = FALSE;
2056 break;
2057 }
2058 }
2059
2060 *out_material = material;
2061 return identical;
2062}
2063
2064BOOL LLSelectMgr::selectionGetClickAction(U8 *out_action)
2065{
2066 LLViewerObject *object = mSelectedObjects.getFirstObject();
2067 if (!object) return FALSE;
2068
2069 U8 action = object->getClickAction();
2070
2071 BOOL identical = TRUE;
2072 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
2073 {
2074 if ( action != object->getClickAction())
2075 {
2076 identical = FALSE;
2077 break;
2078 }
2079 }
2080
2081 *out_action = action;
2082 return identical;
2083}
2084
2085void LLSelectMgr::selectionSetClickAction(U8 action)
2086{
2087 LLViewerObject* object = NULL;
2088 for ( object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
2089 {
2090 object->setClickAction(action);
2091 }
2092 sendListToRegions(
2093 "ObjectClickAction",
2094 packAgentAndSessionID,
2095 packObjectClickAction,
2096 &action,
2097 SEND_INDIVIDUALS);
2098}
2099
2100
2101//-----------------------------------------------------------------------------
2102// godlike requests
2103//-----------------------------------------------------------------------------
2104
2105typedef std::pair<const LLString, const LLString> godlike_request_t;
2106void LLSelectMgr::sendGodlikeRequest(const LLString& request, const LLString& param)
2107{
2108 // If the agent is neither godlike nor an estate owner, the server
2109 // will reject the request.
2110 LLString message_type;
2111 if (gAgent.isGodlike())
2112 {
2113 message_type = "GodlikeMessage";
2114 }
2115 else
2116 {
2117 message_type = "EstateOwnerMessage";
2118 }
2119
2120 godlike_request_t data(request, param);
2121 if(!getRootObjectCount())
2122 {
2123 LLMessageSystem* msg = gMessageSystem;
2124 msg->newMessage(message_type.c_str());
2125 LLSelectMgr::packGodlikeHead(&data);
2126 gAgent.sendReliableMessage();
2127 }
2128 else
2129 {
2130 sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, &data, SEND_ONLY_ROOTS);
2131 }
2132}
2133
2134void LLSelectMgr::packGodlikeHead(void* user_data)
2135{
2136 LLMessageSystem* msg = gMessageSystem;
2137 msg->nextBlockFast(_PREHASH_AgentData);
2138 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2139 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2140 msg->addUUID("TransactionID", LLUUID::null);
2141 godlike_request_t* data = (godlike_request_t*)user_data;
2142 msg->nextBlock("MethodData");
2143 msg->addString("Method", data->first.c_str());
2144 msg->addUUID("Invoice", LLUUID::null);
2145
2146 // The parameters used to be restricted to either string or
2147 // integer. This mimics that behavior under the new 'string-only'
2148 // parameter list by not packing a string if there wasn't one
2149 // specified. The object ids will be packed in the
2150 // packObjectIDAsParam() method.
2151 if(data->second.size() > 0)
2152 {
2153 msg->nextBlock("ParamList");
2154 msg->addString("Parameter", data->second);
2155 }
2156}
2157
2158// static
2159void LLSelectMgr::packObjectIDAsParam(LLSelectNode* node, void *)
2160{
2161 char buf [MAX_STRING];
2162 sprintf(buf, "%u", node->getObject()->getLocalID());
2163 gMessageSystem->nextBlock("ParamList");
2164 gMessageSystem->addString("Parameter", buf);
2165}
2166
2167//-----------------------------------------------------------------------------
2168// Rotation options
2169//-----------------------------------------------------------------------------
2170void LLSelectMgr::selectionResetRotation()
2171{
2172 LLQuaternion identity(0.f, 0.f, 0.f, 1.f);
2173
2174 LLViewerObject* object;
2175 for (object = mSelectedObjects.getFirstRootObject(); object; object = mSelectedObjects.getNextRootObject() )
2176 {
2177 object->setRotation(identity);
2178 if (object->mDrawable.notNull())
2179 {
2180 gPipeline.markMoved(object->mDrawable, TRUE);
2181 }
2182 object->sendRotationUpdate();
2183 }
2184}
2185
2186void LLSelectMgr::selectionRotateAroundZ(F32 degrees)
2187{
2188 LLQuaternion rot( degrees * DEG_TO_RAD, LLVector3(0,0,1) );
2189
2190 LLViewerObject* object;
2191 for (object = mSelectedObjects.getFirstRootObject(); object; object = mSelectedObjects.getNextRootObject() )
2192 {
2193 object->setRotation( object->getRotationEdit() * rot );
2194 if (object->mDrawable.notNull())
2195 {
2196 gPipeline.markMoved(object->mDrawable, TRUE);
2197 }
2198 object->sendRotationUpdate();
2199 }
2200}
2201
2202
2203//-----------------------------------------------------------------------------
2204// selectionTexScaleAutofit()
2205//-----------------------------------------------------------------------------
2206void LLSelectMgr::selectionTexScaleAutofit(F32 repeats_per_meter)
2207{
2208 LLViewerObject* object;
2209 S32 te;
2210 for (mSelectedObjects.getFirstTE(&object, &te); object; mSelectedObjects.getNextTE(&object, &te))
2211 {
2212 if (!object->permModify())
2213 {
2214 continue;
2215 }
2216
2217 if (object->getNumTEs() == 0)
2218 {
2219 continue;
2220 }
2221
2222 // Compute S,T to axis mapping
2223 U32 s_axis, t_axis;
2224 if (!getTESTAxes(object, te, &s_axis, &t_axis))
2225 {
2226 continue;
2227 }
2228
2229 F32 new_s = object->getScale().mV[s_axis] * repeats_per_meter;
2230 F32 new_t = object->getScale().mV[t_axis] * repeats_per_meter;
2231
2232 object->setTEScale(te, new_s, new_t);
2233 }
2234
2235 for (object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject())
2236 {
2237 if (object->permModify())
2238 {
2239 object->sendTEUpdate();
2240 }
2241 }
2242}
2243
2244
2245// BUG: Only works for boxes.
2246// Face numbering for flex boxes as of 1.14.2002
2247//-----------------------------------------------------------------------------
2248// getFaceSTAxes()
2249//-----------------------------------------------------------------------------
2250BOOL LLSelectMgr::getTESTAxes(const LLViewerObject* object, const U8 face, U32* s_axis, U32* t_axis)
2251{
2252 if (face == 0)
2253 {
2254 *s_axis = VX; *t_axis = VY;
2255 return TRUE;
2256 }
2257 else if (face == 1)
2258 {
2259 *s_axis = VX; *t_axis = VZ;
2260 return TRUE;
2261 }
2262 else if (face == 2)
2263 {
2264 *s_axis = VY; *t_axis = VZ;
2265 return TRUE;
2266 }
2267 else if (face == 3)
2268 {
2269 *s_axis = VX; *t_axis = VZ;
2270 return TRUE;
2271 }
2272 else if (face == 4)
2273 {
2274 *s_axis = VY; *t_axis = VZ;
2275 return TRUE;
2276 }
2277 else if (face == 5)
2278 {
2279 *s_axis = VX; *t_axis = VY;
2280 return TRUE;
2281 }
2282 else
2283 {
2284 // unknown face
2285 return FALSE;
2286 }
2287}
2288
2289// Called at the end of a scale operation, this adjusts the textures to attempt to
2290// maintain a constant repeats per meter.
2291// BUG: Only works for flex boxes.
2292//-----------------------------------------------------------------------------
2293// adjustTexturesByScale()
2294//-----------------------------------------------------------------------------
2295void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch)
2296{
2297 LLViewerObject* object;
2298 LLSelectNode* selectNode;
2299
2300 BOOL send = FALSE;
2301
2302 for (selectNode = mSelectedObjects.getFirstNode(); selectNode; selectNode = mSelectedObjects.getNextNode())
2303 {
2304 object = selectNode->getObject();
2305 if (!object->permModify())
2306 {
2307 continue;
2308 }
2309
2310 if (object->getNumTEs() == 0)
2311 {
2312 continue;
2313 }
2314
2315 for (U8 te_num = 0; te_num < object->getNumTEs(); te_num++)
2316 {
2317 const LLTextureEntry* tep = object->getTE(te_num);
2318
2319 BOOL planar = tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR;
2320 if (planar == stretch)
2321 {
2322 // Figure out how S,T changed with scale operation
2323 U32 s_axis, t_axis;
2324 if (!getTESTAxes(object, te_num, &s_axis, &t_axis)) continue;
2325
2326 LLVector3 scale_ratio = selectNode->mTextureScaleRatios[te_num];
2327 LLVector3 object_scale = object->getScale();
2328
2329 // Apply new scale to face
2330 if (planar)
2331 {
2332 object->setTEScale(te_num, 1.f/object_scale.mV[s_axis]*scale_ratio.mV[s_axis],
2333 1.f/object_scale.mV[t_axis]*scale_ratio.mV[t_axis]);
2334 }
2335 else
2336 {
2337 object->setTEScale(te_num, scale_ratio.mV[s_axis]*object_scale.mV[s_axis],
2338 scale_ratio.mV[t_axis]*object_scale.mV[t_axis]);
2339 }
2340 send = send_to_sim;
2341 }
2342 }
2343
2344 if (send)
2345 {
2346 object->sendTEUpdate();
2347 }
2348 }
2349}
2350
2351
2352//-----------------------------------------------------------------------------
2353// selectionResetTexInfo()
2354//-----------------------------------------------------------------------------
2355void LLSelectMgr::selectionResetTexInfo(S32 selected_face)
2356{
2357 S32 start_face, end_face;
2358
2359 LLViewerObject* object;
2360 for (object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject())
2361 {
2362 if (!object->permModify())
2363 {
2364 continue;
2365 }
2366 if (object->getNumTEs() == 0)
2367 {
2368 continue;
2369 }
2370
2371 if (selected_face == -1)
2372 {
2373 start_face = 0;
2374 end_face = object->getNumTEs() - 1;
2375 }
2376 else
2377 {
2378 start_face = selected_face;
2379 end_face = selected_face;
2380 }
2381
2382 for (S32 face = start_face; face <= end_face; face++)
2383 {
2384 // Actually, each object should reset to its appropriate value.
2385 object->setTEScale(face, 1.f, 1.f);
2386 object->setTEOffset(face, 0.f, 0.f);
2387 object->setTERotation(face, 0.f);
2388 }
2389
2390 object->sendTEUpdate();
2391 }
2392}
2393
2394//-----------------------------------------------------------------------------
2395// getFirstEditableObject()
2396//-----------------------------------------------------------------------------
2397LLViewerObject* LLSelectMgr::getFirstEditableObject(BOOL get_root)
2398{
2399 LLViewerObject* object = NULL;
2400 for(LLViewerObject* cur = mSelectedObjects.getFirstObject(); cur; cur = mSelectedObjects.getNextObject())
2401 {
2402 if( cur->permModify() )
2403 {
2404 object = cur;
2405 break;
2406 }
2407 }
2408
2409 if (get_root && object)
2410 {
2411 LLViewerObject *parent;
2412 while ((parent = (LLViewerObject*)object->getParent()))
2413 {
2414 if (parent->isSelected())
2415 {
2416 object = parent;
2417 }
2418 else
2419 {
2420 break;
2421 }
2422 }
2423 }
2424
2425 return object;
2426}
2427
2428//-----------------------------------------------------------------------------
2429// getFirstMoveableObject()
2430//-----------------------------------------------------------------------------
2431LLViewerObject* LLSelectMgr::getFirstMoveableObject(BOOL get_root)
2432{
2433 LLViewerObject* object = NULL;
2434 for(LLViewerObject* cur = mSelectedObjects.getFirstObject(); cur; cur = mSelectedObjects.getNextObject())
2435 {
2436 if( cur->permMove() )
2437 {
2438 object = cur;
2439 break;
2440 }
2441 }
2442
2443 if (get_root && object && !object->isJointChild())
2444 {
2445 LLViewerObject *parent;
2446 while ((parent = (LLViewerObject*)object->getParent()))
2447 {
2448 if (parent->isSelected())
2449 {
2450 object = parent;
2451 }
2452 else
2453 {
2454 break;
2455 }
2456 }
2457 }
2458
2459 return object;
2460}
2461
2462//-----------------------------------------------------------------------------
2463// getFirstEditableNode()
2464//-----------------------------------------------------------------------------
2465LLSelectNode* LLSelectMgr::getFirstEditableNode(BOOL get_root)
2466{
2467 LLSelectNode* selectNode = NULL;
2468
2469 if (get_root)
2470 {
2471 for(selectNode = mSelectedObjects.getFirstRootNode(); selectNode; selectNode = mSelectedObjects.getNextRootNode())
2472 {
2473 if( selectNode->getObject()->permModify() )
2474 {
2475 return selectNode;
2476 break;
2477 }
2478 }
2479 }
2480 for(selectNode = mSelectedObjects.getFirstNode(); selectNode; selectNode = mSelectedObjects.getNextNode())
2481 {
2482 if( selectNode->getObject()->permModify() )
2483 {
2484 return selectNode;
2485 break;
2486 }
2487 }
2488
2489 return NULL;
2490}
2491
2492//-----------------------------------------------------------------------------
2493// getFirstMoveableNode()
2494//-----------------------------------------------------------------------------
2495LLSelectNode* LLSelectMgr::getFirstMoveableNode(BOOL get_root)
2496{
2497 LLSelectNode* selectNode = NULL;
2498
2499 if (get_root)
2500 {
2501 for(selectNode = mSelectedObjects.getFirstRootNode(); selectNode; selectNode = mSelectedObjects.getNextRootNode())
2502 {
2503 if( selectNode->getObject()->permMove() )
2504 {
2505 return selectNode;
2506 break;
2507 }
2508 }
2509 }
2510 for(selectNode = mSelectedObjects.getFirstNode(); selectNode; selectNode = mSelectedObjects.getNextNode())
2511 {
2512 if( selectNode->getObject()->permMove() )
2513 {
2514 return selectNode;
2515 break;
2516 }
2517 }
2518
2519 return NULL;
2520}
2521
2522//-----------------------------------------------------------------------------
2523// getFirstDeleteableObject()
2524//-----------------------------------------------------------------------------
2525LLViewerObject* LLSelectMgr::getFirstDeleteableObject(BOOL get_root)
2526{
2527 //RN: don't currently support deletion of child objects, as that requires separating them first
2528 // then derezzing to trash
2529 get_root = TRUE;
2530
2531 LLViewerObject* object = NULL;
2532 if (get_root)
2533 {
2534 for(LLViewerObject* current = getFirstRootObject();
2535 current != NULL;
2536 current = getNextRootObject())
2537 {
2538 // you can delete an object if permissions allow it, you are
2539 // the owner, you are an officer in the group that owns the
2540 // object, or you are not the owner but it is on land you own
2541 // or land owned by your group. (whew!)
2542 if( (current->permModify())
2543 || (current->permYouOwner())
2544 || (!current->permAnyOwner()) // public
2545 || (current->isOverAgentOwnedLand())
2546 || (current->isOverGroupOwnedLand())
2547 )
2548 {
2549
2550 if( !current->isAttachment() )
2551 {
2552 object = current;
2553 break;
2554 }
2555 }
2556 }
2557 }
2558 else
2559 {
2560 for(LLViewerObject* current = getFirstObject();
2561 current != NULL;
2562 current = getNextObject())
2563 {
2564 // you can delete an object if permissions allow it, you are
2565 // the owner, you are an officer in the group that owns the
2566 // object, or you are not the owner but it is on land you own
2567 // or land owned by your group. (whew!)
2568 if( (current->permModify())
2569 || (current->permYouOwner())
2570 || (!current->permAnyOwner()) // public
2571 || (current->isOverAgentOwnedLand())
2572 || (current->isOverGroupOwnedLand())
2573 )
2574 {
2575 if( !current->isAttachment() )
2576 {
2577 object = current;
2578 break;
2579 }
2580 }
2581 }
2582 }
2583
2584 return object;
2585}
2586
2587//-----------------------------------------------------------------------------
2588// getFirstCopyableObject()
2589//-----------------------------------------------------------------------------
2590LLViewerObject* LLSelectMgr::getFirstCopyableObject(BOOL get_root)
2591{
2592 LLViewerObject* object = NULL;
2593 for(LLViewerObject* cur = mSelectedObjects.getFirstObject(); cur; cur = mSelectedObjects.getNextObject())
2594 {
2595 if( cur->permCopy() && !cur->isAttachment())
2596 {
2597 object = cur;
2598 break;
2599 }
2600 }
2601
2602 if (get_root && object)
2603 {
2604 LLViewerObject *parent;
2605 while ((parent = (LLViewerObject*)object->getParent()))
2606 {
2607 if (parent->isSelected())
2608 {
2609 object = parent;
2610 }
2611 else
2612 {
2613 break;
2614 }
2615 }
2616 }
2617
2618 return object;
2619}
2620
2621//-----------------------------------------------------------------------------
2622// areMultpleEditableObjectsSelected()
2623//-----------------------------------------------------------------------------
2624BOOL LLSelectMgr::areMultpleEditableObjectsSelected()
2625{
2626 S32 count = 0;
2627 for( LLViewerObject* cur = mSelectedObjects.getFirstObject(); cur; cur = mSelectedObjects.getNextObject() )
2628 {
2629 if( cur->permModify() )
2630 {
2631 count++;
2632 if( count > 1 )
2633 {
2634 return TRUE;
2635 }
2636 }
2637 }
2638 return FALSE;
2639}
2640
2641//-----------------------------------------------------------------------------
2642// selectGetAllRootsValid()
2643// Returns true if the viewer has information on all selected objects
2644//-----------------------------------------------------------------------------
2645BOOL LLSelectMgr::selectGetAllRootsValid()
2646{
2647 for( LLSelectNode* node = getFirstRootNode(); node; node = getNextRootNode() )
2648 {
2649
2650 if( !node->mValid )
2651 {
2652 return FALSE;
2653 }
2654
2655 if( !node->getObject() )
2656 {
2657 return FALSE;
2658 }
2659 }
2660 return TRUE;
2661}
2662
2663
2664//-----------------------------------------------------------------------------
2665// selectGetAllValid()
2666// Returns true if the viewer has information on all selected objects
2667//-----------------------------------------------------------------------------
2668BOOL LLSelectMgr::selectGetAllValid()
2669{
2670 for( LLSelectNode* node = getFirstNode(); node; node = getNextNode() )
2671 {
2672
2673 if( !node->mValid )
2674 {
2675 return FALSE;
2676 }
2677
2678 if( !node->getObject() )
2679 {
2680 return FALSE;
2681 }
2682 }
2683 return TRUE;
2684}
2685
2686
2687//-----------------------------------------------------------------------------
2688// selectGetModify() - return true if current agent can modify all
2689// selected objects.
2690//-----------------------------------------------------------------------------
2691BOOL LLSelectMgr::selectGetModify()
2692{
2693 for( LLSelectNode* node = getFirstNode(); node; node = getNextNode() )
2694 {
2695 if( !node->mValid )
2696 {
2697 return FALSE;
2698 }
2699 LLViewerObject* object = node->getObject();
2700 if( !object || !object->permModify() )
2701 {
2702 return FALSE;
2703 }
2704 }
2705
2706 return TRUE;
2707}
2708
2709//-----------------------------------------------------------------------------
2710// selectGetRootsModify() - return true if current agent can modify all
2711// selected root objects.
2712//-----------------------------------------------------------------------------
2713BOOL LLSelectMgr::selectGetRootsModify()
2714{
2715 for( LLSelectNode* node = getFirstRootNode(); node; node = getNextRootNode() )
2716 {
2717 if( !node->mValid )
2718 {
2719 return FALSE;
2720 }
2721 LLViewerObject* object = node->getObject();
2722 if( !object || !object->permModify() )
2723 {
2724 return FALSE;
2725 }
2726 }
2727
2728 return TRUE;
2729}
2730
2731
2732//-----------------------------------------------------------------------------
2733// selectGetRootsTransfer() - return true if current agent can transfer all
2734// selected root objects.
2735//-----------------------------------------------------------------------------
2736BOOL LLSelectMgr::selectGetRootsTransfer()
2737{
2738 for(LLSelectNode* node = getFirstRootNode(); node; node = getNextRootNode())
2739 {
2740 if(!node->mValid)
2741 {
2742 return FALSE;
2743 }
2744 LLViewerObject* object = node->getObject();
2745 if(!object || !object->permTransfer())
2746 {
2747 return FALSE;
2748 }
2749 }
2750 return TRUE;
2751}
2752
2753//-----------------------------------------------------------------------------
2754// selectGetRootsCopy() - return true if current agent can copy all
2755// selected root objects.
2756//-----------------------------------------------------------------------------
2757BOOL LLSelectMgr::selectGetRootsCopy()
2758{
2759 for(LLSelectNode* node = getFirstRootNode(); node; node = getNextRootNode())
2760 {
2761 if(!node->mValid)
2762 {
2763 return FALSE;
2764 }
2765 LLViewerObject* object = node->getObject();
2766 if(!object || !object->permCopy())
2767 {
2768 return FALSE;
2769 }
2770 }
2771 return TRUE;
2772}
2773
2774//-----------------------------------------------------------------------------
2775// selectGetCreator()
2776// Creator information only applies to root objects.
2777//-----------------------------------------------------------------------------
2778BOOL LLSelectMgr::selectGetCreator(LLUUID& id, LLString& name)
2779{
2780 LLSelectNode* node = getFirstRootNode();
2781 if(!node) node = getFirstNode();
2782 if(!node) return FALSE;
2783 if(!node->mValid) return FALSE;
2784 LLViewerObject* obj = node->getObject();
2785 if(!obj) return FALSE;
2786 if(!(obj->isRoot() || obj->isJointChild())) return FALSE;
2787
2788 id = node->mPermissions->getCreator();
2789
2790 BOOL identical = TRUE;
2791 for ( node = getNextRootNode(); node; node = getNextRootNode() )
2792 {
2793 if (!node->mValid)
2794 {
2795 identical = FALSE;
2796 break;
2797 }
2798
2799 if ( !(id == node->mPermissions->getCreator() ) )
2800 {
2801 identical = FALSE;
2802 break;
2803 }
2804 }
2805
2806 if (identical)
2807 {
2808 char firstname[DB_FIRST_NAME_BUF_SIZE];
2809 char lastname[DB_LAST_NAME_BUF_SIZE];
2810 gCacheName->getName(id, firstname, lastname);
2811 name.assign( firstname );
2812 name.append( " " );
2813 name.append( lastname );
2814 }
2815 else
2816 {
2817 name.assign( "(multiple)" );
2818 }
2819
2820 return identical;
2821}
2822
2823
2824//-----------------------------------------------------------------------------
2825// selectGetOwner()
2826// Owner information only applies to roots.
2827//-----------------------------------------------------------------------------
2828BOOL LLSelectMgr::selectGetOwner(LLUUID& id, LLString& name)
2829{
2830 LLSelectNode* node = getFirstRootNode();
2831 if(!node) node = getFirstNode();
2832 if(!node) return FALSE;
2833 if(!node->mValid) return FALSE;
2834 LLViewerObject* obj = node->getObject();
2835 if(!obj) return FALSE;
2836 if(!(obj->isRootEdit() || obj->isRoot() || obj->isJointChild())) return FALSE;
2837
2838 BOOL group_owner = FALSE;
2839 id.setNull();
2840 node->mPermissions->getOwnership(id, group_owner);
2841
2842 BOOL identical = TRUE;
2843 for ( node = getNextRootNode(); node; node = getNextRootNode() )
2844 {
2845 if (!node->mValid)
2846 {
2847 identical = FALSE;
2848 break;
2849 }
2850
2851 LLUUID owner_id;
2852 BOOL is_group_owned = FALSE;
2853 if (!(node->mPermissions->getOwnership(owner_id, is_group_owned))
2854 || owner_id != id )
2855 {
2856 identical = FALSE;
2857 break;
2858 }
2859 }
2860
2861 BOOL public_owner = (id.isNull() && !group_owner);
2862
2863 if (identical)
2864 {
2865 if (group_owner)
2866 {
2867 name.assign( "(Group Owned)");
2868 }
2869 else if(!public_owner)
2870 {
2871 char firstname[DB_FIRST_NAME_BUF_SIZE];
2872 char lastname[DB_LAST_NAME_BUF_SIZE];
2873 gCacheName->getName(id, firstname, lastname);
2874 name.assign( firstname );
2875 name.append( " " );
2876 name.append( lastname );
2877 }
2878 else
2879 {
2880 name.assign("Public");
2881 }
2882 }
2883 else
2884 {
2885 name.assign( "(multiple)" );
2886 }
2887
2888 return identical;
2889}
2890
2891
2892//-----------------------------------------------------------------------------
2893// selectGetLastOwner()
2894// Owner information only applies to roots.
2895//-----------------------------------------------------------------------------
2896BOOL LLSelectMgr::selectGetLastOwner(LLUUID& id, LLString& name)
2897{
2898 LLSelectNode* node = getFirstRootNode();
2899 if(!node) node = getFirstNode();
2900 if(!node) return FALSE;
2901 if(!node->mValid) return FALSE;
2902 LLViewerObject* obj = node->getObject();
2903 if(!obj) return FALSE;
2904 if(!(obj->isRoot() || obj->isJointChild())) return FALSE;
2905
2906 id = node->mPermissions->getLastOwner();
2907
2908 BOOL identical = TRUE;
2909 for ( node = getNextRootNode(); node; node = getNextRootNode() )
2910 {
2911 if (!node->mValid)
2912 {
2913 identical = FALSE;
2914 break;
2915 }
2916
2917 if ( !(id == node->mPermissions->getLastOwner() ) )
2918 {
2919 identical = FALSE;
2920 break;
2921 }
2922 }
2923
2924 BOOL public_owner = (id.isNull());
2925
2926 if (identical)
2927 {
2928 if(!public_owner)
2929 {
2930 char firstname[DB_FIRST_NAME_BUF_SIZE];
2931 char lastname[DB_LAST_NAME_BUF_SIZE];
2932 gCacheName->getName(id, firstname, lastname);
2933 name.assign( firstname );
2934 name.append( " " );
2935 name.append( lastname );
2936 }
2937 else
2938 {
2939 name.assign("Public or Group");
2940 }
2941 }
2942 else
2943 {
2944 name.assign( "" );
2945 }
2946
2947 return identical;
2948}
2949
2950
2951//-----------------------------------------------------------------------------
2952// selectGetGroup()
2953// Group information only applies to roots.
2954//-----------------------------------------------------------------------------
2955BOOL LLSelectMgr::selectGetGroup(LLUUID& id)
2956{
2957 LLSelectNode* node = getFirstRootNode();
2958 if(!node) node = getFirstNode();
2959 if(!node) return FALSE;
2960 if(!node->mValid) return FALSE;
2961 LLViewerObject* obj = node->getObject();
2962 if(!obj) return FALSE;
2963 if(!(obj->isRoot() || obj->isJointChild())) return FALSE;
2964
2965 id = node->mPermissions->getGroup();
2966
2967 BOOL identical = TRUE;
2968 for ( node = getNextRootNode(); node; node = getNextRootNode() )
2969 {
2970 if (!node->mValid)
2971 {
2972 identical = FALSE;
2973 break;
2974 }
2975
2976 if ( !(id == node->mPermissions->getGroup() ) )
2977 {
2978 identical = FALSE;
2979 break;
2980 }
2981 }
2982
2983 return identical;
2984}
2985
2986//-----------------------------------------------------------------------------
2987// selectIsGroupOwned()
2988// Only operates on root nodes.
2989// Returns TRUE if all have valid data and they are all group owned.
2990//-----------------------------------------------------------------------------
2991BOOL LLSelectMgr::selectIsGroupOwned()
2992{
2993 LLSelectNode* node = getFirstRootNode();
2994 if(!node) node = getFirstNode();
2995 if(!node) return FALSE;
2996 if(!node->mValid) return FALSE;
2997 LLViewerObject* obj = node->getObject();
2998 if(!obj) return FALSE;
2999 if(!(obj->isRoot() || obj->isJointChild())) return FALSE;
3000
3001 BOOL is_group_owned = node->mPermissions->isGroupOwned();
3002
3003 if(is_group_owned)
3004 {
3005 for ( node = getNextRootNode(); node; node = getNextRootNode() )
3006 {
3007 if (!node->mValid)
3008 {
3009 is_group_owned = FALSE;
3010 break;
3011 }
3012
3013 if ( !( node->mPermissions->isGroupOwned() ) )
3014 {
3015 is_group_owned = FALSE;
3016 break;
3017 }
3018 }
3019 }
3020 return is_group_owned;
3021}
3022
3023//-----------------------------------------------------------------------------
3024// selectGetPerm()
3025// Only operates on root nodes.
3026// Returns TRUE if all have valid data.
3027// mask_on has bits set to true where all permissions are true
3028// mask_off has bits set to true where all permissions are false
3029// if a bit is off both in mask_on and mask_off, the values differ within
3030// the selection.
3031//-----------------------------------------------------------------------------
3032BOOL LLSelectMgr::selectGetPerm(U8 which_perm, U32* mask_on, U32* mask_off)
3033{
3034 LLSelectNode* node = getFirstRootNode();
3035 if (!node) return FALSE;
3036 if (!node->mValid) return FALSE;
3037
3038 U32 mask;
3039 U32 mask_and = 0xffffffff;
3040 U32 mask_or = 0x00000000;
3041 BOOL all_valid = TRUE;
3042
3043 for ( node = getFirstRootNode(); node; node = getNextRootNode() )
3044 {
3045 if (!node->mValid)
3046 {
3047 all_valid = FALSE;
3048 break;
3049 }
3050
3051 switch( which_perm )
3052 {
3053 case PERM_BASE:
3054 mask = node->mPermissions->getMaskBase();
3055 break;
3056 case PERM_OWNER:
3057 mask = node->mPermissions->getMaskOwner();
3058 break;
3059 case PERM_GROUP:
3060 mask = node->mPermissions->getMaskGroup();
3061 break;
3062 case PERM_EVERYONE:
3063 mask = node->mPermissions->getMaskEveryone();
3064 break;
3065 case PERM_NEXT_OWNER:
3066 mask = node->mPermissions->getMaskNextOwner();
3067 break;
3068 default:
3069 mask = 0x0;
3070 break;
3071 }
3072 mask_and &= mask;
3073 mask_or |= mask;
3074 }
3075
3076 if (all_valid)
3077 {
3078 // ...true through all ANDs means all true
3079 *mask_on = mask_and;
3080
3081 // ...false through all ORs means all false
3082 *mask_off = ~mask_or;
3083 return TRUE;
3084 }
3085 else
3086 {
3087 *mask_on = 0;
3088 *mask_off = 0;
3089 return FALSE;
3090 }
3091}
3092
3093
3094
3095BOOL LLSelectMgr::selectGetOwnershipCost(S32* out_cost)
3096{
3097 return mSelectedObjects.getOwnershipCost(*out_cost);
3098}
3099
3100BOOL LLSelectMgr::selectGetPermissions(LLPermissions& perm)
3101{
3102 LLSelectNode* node = getFirstRootNode();
3103 if (!node) return FALSE;
3104 if (!node->mValid) return FALSE;
3105 BOOL valid = TRUE;
3106 perm = *(node->mPermissions);
3107 for(node = getNextRootNode(); node != NULL; node = getNextRootNode())
3108 {
3109 if(!node->mValid)
3110 {
3111 valid = FALSE;
3112 break;
3113 }
3114 perm.accumulate(*(node->mPermissions));
3115 }
3116 return valid;
3117}
3118
3119
3120void LLSelectMgr::selectDelete()
3121{
3122 S32 deleteable_count = 0;
3123
3124 BOOL locked_but_deleteable_object = FALSE;
3125 BOOL no_copy_but_deleteable_object = FALSE;
3126 BOOL all_owned_by_you = TRUE;
3127 for(LLViewerObject* obj = getFirstObject();
3128 obj != NULL;
3129 obj = getNextObject())
3130 {
3131 if( obj->isAttachment() )
3132 {
3133 continue;
3134 }
3135
3136 deleteable_count++;
3137
3138 // Check to see if you can delete objects which are locked.
3139 if(!obj->permMove())
3140 {
3141 locked_but_deleteable_object = TRUE;
3142 }
3143 if(!obj->permCopy())
3144 {
3145 no_copy_but_deleteable_object = TRUE;
3146 }
3147 if(!obj->permYouOwner())
3148 {
3149 all_owned_by_you = FALSE;
3150 }
3151 }
3152
3153 if( 0 == deleteable_count )
3154 {
3155 make_ui_sound("UISndInvalidOp");
3156 return;
3157 }
3158
3159 if(locked_but_deleteable_object ||
3160 no_copy_but_deleteable_object ||
3161 !all_owned_by_you)
3162 {
3163 // convert any transient pie-menu selections to full selection so this operation
3164 // has some context
3165 // NOTE: if user cancels delete operation, this will potentially leave objects selected outside of build mode
3166 // but this is ok, if not ideal
3167 convertTransient();
3168
3169 //This is messy, but needed to get all english our of the UI.
3170 if(locked_but_deleteable_object && !no_copy_but_deleteable_object && all_owned_by_you)
3171 {
3172 //Locked only
3173 gViewerWindow->alertXml( "ConfirmObjectDeleteLock",
3174 &LLSelectMgr::confirmDelete,
3175 this);
3176 }
3177 else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you)
3178 {
3179 //No Copy only
3180 gViewerWindow->alertXml( "ConfirmObjectDeleteNoCopy",
3181 &LLSelectMgr::confirmDelete,
3182 this);
3183 }
3184 else if(!locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you)
3185 {
3186 //not owned only
3187 gViewerWindow->alertXml( "ConfirmObjectDeleteNoOwn",
3188 &LLSelectMgr::confirmDelete,
3189 this);
3190 }
3191 else if(locked_but_deleteable_object && no_copy_but_deleteable_object && all_owned_by_you)
3192 {
3193 //locked and no copy
3194 gViewerWindow->alertXml( "ConfirmObjectDeleteLockNoCopy",
3195 &LLSelectMgr::confirmDelete,
3196 this);
3197 }
3198 else if(locked_but_deleteable_object && !no_copy_but_deleteable_object && !all_owned_by_you)
3199 {
3200 //locked and not owned
3201 gViewerWindow->alertXml( "ConfirmObjectDeleteLockNoOwn",
3202 &LLSelectMgr::confirmDelete,
3203 this);
3204 }
3205 else if(!locked_but_deleteable_object && no_copy_but_deleteable_object && !all_owned_by_you)
3206 {
3207 //no copy and not owned
3208 gViewerWindow->alertXml( "ConfirmObjectDeleteNoCopyNoOwn",
3209 &LLSelectMgr::confirmDelete,
3210 this);
3211 }
3212 else
3213 {
3214 //locked, no copy and not owned
3215 gViewerWindow->alertXml( "ConfirmObjectDeleteLockNoCopyNoOwn",
3216 &LLSelectMgr::confirmDelete,
3217 this);
3218 }
3219
3220
3221
3222 }
3223 else
3224 {
3225 confirmDelete(0, (void*)this);
3226 }
3227}
3228
3229// static
3230void LLSelectMgr::confirmDelete(S32 option, void* data)
3231{
3232 LLSelectMgr* self = (LLSelectMgr*)data;
3233 if(!self) return;
3234 switch(option)
3235 {
3236 case 0:
3237 {
3238 // TODO: Make sure you have delete permissions on all of them.
3239 LLUUID trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
3240 // attempt to derez into the trash.
3241 LLDeRezInfo* info = new LLDeRezInfo(DRD_TRASH, trash_id);
3242 self->sendListToRegions("DeRezObject",
3243 packDeRezHeader,
3244 packObjectLocalID,
3245 (void*)info,
3246 SEND_ONLY_ROOTS);
3247 // VEFFECT: Delete Object - one effect for all deletes
3248 if (self->mSelectType != SELECT_TYPE_HUD)
3249 {
3250 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
3251 effectp->setPositionGlobal( self->getSelectionCenterGlobal() );
3252 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
3253 F32 duration = 0.5f;
3254 duration += self->getObjectCount() / 64.f;
3255 effectp->setDuration(duration);
3256 }
3257
3258 gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
3259
3260 // Keep track of how many objects have been deleted.
3261 F64 obj_delete_count = gViewerStats->getStat(LLViewerStats::ST_OBJECT_DELETE_COUNT);
3262 obj_delete_count += self->getObjectCount();
3263 gViewerStats->setStat(LLViewerStats::ST_OBJECT_DELETE_COUNT, obj_delete_count );
3264 }
3265 break;
3266 case 1:
3267 default:
3268 break;
3269 }
3270}
3271
3272
3273void LLSelectMgr::selectForceDelete()
3274{
3275 sendListToRegions(
3276 "ObjectDelete",
3277 packDeleteHeader,
3278 packObjectLocalID,
3279 (void*)TRUE,
3280 SEND_ONLY_ROOTS);
3281}
3282
3283
3284// returns TRUE if anything is for sale. calculates the total price
3285// and stores that value in price.
3286BOOL LLSelectMgr::selectIsForSale(S32& price)
3287{
3288 BOOL any_for_sale = FALSE;
3289 price = 0;
3290
3291 LLSelectNode *node;
3292 for (node = getFirstRootNode(); node; node = getNextRootNode() )
3293 {
3294 if (node->mSaleInfo.isForSale())
3295 {
3296 price += node->mSaleInfo.getSalePrice();
3297 any_for_sale = TRUE;
3298 }
3299 }
3300
3301 return any_for_sale;
3302
3303}
3304
3305// returns TRUE if all nodes are valid. method also stores an
3306// accumulated sale info.
3307BOOL LLSelectMgr::selectGetSaleInfo(LLSaleInfo& sale_info)
3308{
3309 LLSelectNode* node = getFirstRootNode();
3310 if (!node) return FALSE;
3311 if (!node->mValid) return FALSE;
3312 BOOL valid = TRUE;
3313 sale_info = node->mSaleInfo;
3314 for(node = getNextRootNode(); node != NULL; node = getNextRootNode())
3315 {
3316 if(!node->mValid)
3317 {
3318 valid = FALSE;
3319 break;
3320 }
3321 sale_info.accumulate(node->mSaleInfo);
3322 }
3323 return valid;
3324}
3325
3326BOOL LLSelectMgr::selectGetAggregatePermissions(LLAggregatePermissions& ag_perm)
3327{
3328 LLSelectNode* node = getFirstNode();
3329 if (!node) return FALSE;
3330 if (!node->mValid) return FALSE;
3331 BOOL valid = TRUE;
3332 ag_perm = node->mAggregatePerm;
3333 for(node = getNextNode(); node != NULL; node = getNextNode())
3334 {
3335 if(!node->mValid)
3336 {
3337 valid = FALSE;
3338 break;
3339 }
3340 ag_perm.aggregate(node->mAggregatePerm);
3341 }
3342 return valid;
3343}
3344
3345BOOL LLSelectMgr::selectGetAggregateTexturePermissions(LLAggregatePermissions& ag_perm)
3346{
3347 LLSelectNode* node = getFirstNode();
3348 if (!node) return FALSE;
3349 if (!node->mValid) return FALSE;
3350 BOOL valid = TRUE;
3351 ag_perm = node->getObject()->permYouOwner() ? node->mAggregateTexturePermOwner : node->mAggregateTexturePerm;
3352 for(node = getNextNode(); node != NULL; node = getNextNode())
3353 {
3354 if(!node->mValid)
3355 {
3356 valid = FALSE;
3357 break;
3358 }
3359 ag_perm.aggregate(node->getObject()->permYouOwner() ? node->mAggregateTexturePermOwner : node->mAggregateTexturePerm);
3360 }
3361 return valid;
3362}
3363
3364
3365// returns TRUE is any node is currenly worn as an attachment
3366BOOL LLSelectMgr::selectionIsAttachment()
3367{
3368 return (mSelectType == SELECT_TYPE_ATTACHMENT || mSelectType == SELECT_TYPE_HUD);
3369}
3370
3371//--------------------------------------------------------------------
3372// Duplicate objects
3373//--------------------------------------------------------------------
3374
3375// JC - If this doesn't work right, duplicate the selection list
3376// before doing anything, do a deselect, then send the duplicate
3377// messages.
3378struct LLDuplicateData
3379{
3380 LLVector3 offset;
3381 U32 flags;
3382};
3383
3384void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy)
3385{
3386 if (selectionIsAttachment())
3387 {
3388 //RN: do not duplicate attachments
3389 make_ui_sound("UISndInvalidOp");
3390 return;
3391 }
3392 LLDuplicateData data;
3393
3394 data.offset = offset;
3395 data.flags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0);
3396
3397 sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, &data, SEND_ONLY_ROOTS);
3398
3399 if (select_copy)
3400 {
3401 // the new copy will be coming in selected
3402 deselectAll();
3403 }
3404 else
3405 {
3406 for (LLSelectNode* node = getFirstRootNode(); node; node = getNextRootNode())
3407 {
3408 node->mDuplicated = TRUE;
3409 node->mDuplicatePos = node->getObject()->getPositionGlobal();
3410 node->mDuplicateRot = node->getObject()->getRotation();
3411 }
3412 }
3413}
3414
3415void LLSelectMgr::repeatDuplicate()
3416{
3417 if (selectionIsAttachment())
3418 {
3419 //RN: do not duplicate attachments
3420 make_ui_sound("UISndInvalidOp");
3421 return;
3422 }
3423
3424 LLSelectNode* node;
3425 LLDynamicArray<LLViewerObject*> non_duplicated_objects;
3426
3427 for (node = getFirstRootNode(); node; node = getNextRootNode())
3428 {
3429 if (!node->mDuplicated)
3430 {
3431 non_duplicated_objects.put(node->getObject());
3432 }
3433 }
3434
3435 // make sure only previously duplicated objects are selected
3436 for (S32 i = 0; i < non_duplicated_objects.count(); i++)
3437 {
3438 deselectObjectAndFamily(non_duplicated_objects[i]);
3439 }
3440
3441 // duplicate objects in place
3442 LLDuplicateData data;
3443
3444 data.offset = LLVector3::zero;
3445 data.flags = 0x0;
3446
3447 sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, &data, SEND_ONLY_ROOTS);
3448
3449 // move current selection based on delta from duplication position and update duplication position
3450 for (node = getFirstRootNode(); node; node = getNextRootNode())
3451 {
3452 if (node->mDuplicated)
3453 {
3454 LLQuaternion cur_rot = node->getObject()->getRotation();
3455 LLQuaternion rot_delta = (~node->mDuplicateRot * cur_rot);
3456 LLQuaternion new_rot = cur_rot * rot_delta;
3457 LLVector3d cur_pos = node->getObject()->getPositionGlobal();
3458 LLVector3d new_pos = cur_pos + ((cur_pos - node->mDuplicatePos) * rot_delta);
3459
3460 node->mDuplicatePos = node->getObject()->getPositionGlobal();
3461 node->mDuplicateRot = node->getObject()->getRotation();
3462 node->getObject()->setPositionGlobal(new_pos);
3463 node->getObject()->setRotation(new_rot);
3464 }
3465 }
3466
3467 sendMultipleUpdate(UPD_ROTATION | UPD_POSITION);
3468}
3469
3470// static
3471void LLSelectMgr::packDuplicate( LLSelectNode* node, void *duplicate_data )
3472{
3473 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3474 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID());
3475}
3476
3477
3478//--------------------------------------------------------------------
3479// Duplicate On Ray
3480//--------------------------------------------------------------------
3481
3482// Duplicates the selected objects, but places the copy along a cast
3483// ray.
3484struct LLDuplicateOnRayData
3485{
3486 LLVector3 mRayStartRegion;
3487 LLVector3 mRayEndRegion;
3488 BOOL mBypassRaycast;
3489 BOOL mRayEndIsIntersection;
3490 LLUUID mRayTargetID;
3491 BOOL mCopyCenters;
3492 BOOL mCopyRotates;
3493 U32 mFlags;
3494};
3495
3496void LLSelectMgr::selectDuplicateOnRay(const LLVector3 &ray_start_region,
3497 const LLVector3 &ray_end_region,
3498 BOOL bypass_raycast,
3499 BOOL ray_end_is_intersection,
3500 const LLUUID &ray_target_id,
3501 BOOL copy_centers,
3502 BOOL copy_rotates,
3503 BOOL select_copy)
3504{
3505 if (selectionIsAttachment())
3506 {
3507 // do not duplicate attachments
3508 make_ui_sound("UISndInvalidOp");
3509 return;
3510 }
3511
3512 LLDuplicateOnRayData data;
3513
3514 data.mRayStartRegion = ray_start_region;
3515 data.mRayEndRegion = ray_end_region;
3516 data.mBypassRaycast = bypass_raycast;
3517 data.mRayEndIsIntersection = ray_end_is_intersection;
3518 data.mRayTargetID = ray_target_id;
3519 data.mCopyCenters = copy_centers;
3520 data.mCopyRotates = copy_rotates;
3521 data.mFlags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0);
3522
3523 sendListToRegions("ObjectDuplicateOnRay",
3524 packDuplicateOnRayHead, packObjectLocalID, &data, SEND_ONLY_ROOTS);
3525
3526 if (select_copy)
3527 {
3528 // the new copy will be coming in selected
3529 deselectAll();
3530 }
3531}
3532
3533// static
3534void LLSelectMgr::packDuplicateOnRayHead(void *user_data)
3535{
3536 LLMessageSystem *msg = gMessageSystem;
3537 LLDuplicateOnRayData *data = (LLDuplicateOnRayData *)user_data;
3538
3539 msg->nextBlockFast(_PREHASH_AgentData);
3540 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3541 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
3542 msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() );
3543 msg->addVector3Fast(_PREHASH_RayStart, data->mRayStartRegion );
3544 msg->addVector3Fast(_PREHASH_RayEnd, data->mRayEndRegion );
3545 msg->addBOOLFast(_PREHASH_BypassRaycast, data->mBypassRaycast );
3546 msg->addBOOLFast(_PREHASH_RayEndIsIntersection, data->mRayEndIsIntersection );
3547 msg->addBOOLFast(_PREHASH_CopyCenters, data->mCopyCenters );
3548 msg->addBOOLFast(_PREHASH_CopyRotates, data->mCopyRotates );
3549 msg->addUUIDFast(_PREHASH_RayTargetID, data->mRayTargetID );
3550 msg->addU32Fast(_PREHASH_DuplicateFlags, data->mFlags );
3551}
3552
3553
3554
3555//------------------------------------------------------------------------
3556// Object position, scale, rotation update, all-in-one
3557//------------------------------------------------------------------------
3558
3559void LLSelectMgr::sendMultipleUpdate(U32 type)
3560{
3561 if (type == UPD_NONE) return;
3562 // send individual updates when selecting textures or individual objects
3563 ESendType send_type = (gSavedSettings.getBOOL("SelectLinkedSet") && !getTEMode()) ? SEND_ONLY_ROOTS : SEND_ROOTS_FIRST;
3564 if (send_type == SEND_ONLY_ROOTS)
3565 {
3566 // tell simulator to apply to whole linked sets
3567 type |= UPD_LINKED_SETS;
3568 }
3569
3570 sendListToRegions(
3571 "MultipleObjectUpdate",
3572 packAgentAndSessionID,
3573 packMultipleUpdate,
3574 &type,
3575 send_type);
3576}
3577
3578// static
3579void LLSelectMgr::packMultipleUpdate(LLSelectNode* node, void *user_data)
3580{
3581 LLViewerObject* object = node->getObject();
3582 U32 *type32 = (U32 *)user_data;
3583 U8 type = (U8)*type32;
3584 U8 data[256];
3585
3586 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3587 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
3588 gMessageSystem->addU8Fast(_PREHASH_Type, type );
3589
3590 S32 offset = 0;
3591
3592 // JC: You MUST pack the data in this order. The receiving
3593 // routine process_multiple_update_message on simulator will
3594 // extract them in this order.
3595
3596 if (type & UPD_POSITION)
3597 {
3598 htonmemcpy(&data[offset], &(object->getPosition().mV), MVT_LLVector3, 12);
3599 offset += 12;
3600 }
3601 if (type & UPD_ROTATION)
3602 {
3603 LLQuaternion quat = object->getRotation();
3604 LLVector3 vec = quat.packToVector3();
3605 htonmemcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12);
3606 offset += 12;
3607 }
3608 if (type & UPD_SCALE)
3609 {
3610 //llinfos << "Sending object scale " << object->getScale() << llendl;
3611 htonmemcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12);
3612 offset += 12;
3613 }
3614 gMessageSystem->addBinaryDataFast(_PREHASH_Data, data, offset);
3615}
3616
3617//------------------------------------------------------------------------
3618// Ownership
3619//------------------------------------------------------------------------
3620struct LLOwnerData
3621{
3622 LLUUID owner_id;
3623 LLUUID group_id;
3624 BOOL override;
3625};
3626
3627void LLSelectMgr::sendOwner(const LLUUID& owner_id,
3628 const LLUUID& group_id,
3629 BOOL override)
3630{
3631 LLOwnerData data;
3632
3633 data.owner_id = owner_id;
3634 data.group_id = group_id;
3635 data.override = override;
3636
3637 sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, &data, SEND_ONLY_ROOTS);
3638}
3639
3640// static
3641void LLSelectMgr::packOwnerHead(void *user_data)
3642{
3643 LLOwnerData *data = (LLOwnerData *)user_data;
3644
3645 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3646 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3647 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
3648 gMessageSystem->nextBlockFast(_PREHASH_HeaderData);
3649 gMessageSystem->addBOOLFast(_PREHASH_Override, data->override);
3650 gMessageSystem->addUUIDFast(_PREHASH_OwnerID, data->owner_id);
3651 gMessageSystem->addUUIDFast(_PREHASH_GroupID, data->group_id);
3652}
3653
3654//------------------------------------------------------------------------
3655// Group
3656//------------------------------------------------------------------------
3657
3658void LLSelectMgr::sendGroup(const LLUUID& group_id)
3659{
3660 LLUUID local_group_id(group_id);
3661 sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, &local_group_id, SEND_ONLY_ROOTS);
3662}
3663
3664
3665//------------------------------------------------------------------------
3666// Buy
3667//------------------------------------------------------------------------
3668
3669struct LLBuyData
3670{
3671 LLDynamicArray<LLViewerObject*> mObjectsSent;
3672 LLUUID mCategoryID;
3673 LLSaleInfo mSaleInfo;
3674};
3675
3676// *NOTE: does not work for multiple object buy, which UI does not
3677// currently support sale info is used for verification only, if it
3678// doesn't match region info then sale is canceled Need to get sale
3679// info -as displayed in the UI- for every item.
3680void LLSelectMgr::sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, const LLSaleInfo sale_info)
3681{
3682 LLBuyData buy;
3683 buy.mCategoryID = category_id;
3684 buy.mSaleInfo = sale_info;
3685 sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, &buy, SEND_ONLY_ROOTS);
3686}
3687
3688// static
3689void LLSelectMgr::packBuyObjectIDs(LLSelectNode* node, void* data)
3690{
3691 LLBuyData* buy = (LLBuyData*)data;
3692
3693 LLViewerObject* object = node->getObject();
3694 if(buy->mObjectsSent.find(object) == LLDynamicArray<LLViewerObject*>::FAIL)
3695 {
3696 buy->mObjectsSent.put(object);
3697 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3698 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() );
3699 gMessageSystem->addU8Fast(_PREHASH_SaleType, buy->mSaleInfo.getSaleType());
3700 gMessageSystem->addS32Fast(_PREHASH_SalePrice, buy->mSaleInfo.getSalePrice());
3701 }
3702}
3703
3704//------------------------------------------------------------------------
3705// Permissions
3706//------------------------------------------------------------------------
3707
3708struct LLPermData
3709{
3710 U8 mField;
3711 BOOL mSet;
3712 U32 mMask;
3713 BOOL mOverride;
3714};
3715
3716// TODO: Make this able to fail elegantly.
3717void LLSelectMgr::setObjectPermissions(U8 field,
3718 BOOL set,
3719 U32 mask,
3720 BOOL override)
3721{
3722 LLPermData data;
3723
3724 data.mField = field;
3725 data.mSet = set;
3726 data.mMask = mask;
3727 data.mOverride = override;
3728
3729 sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, &data, SEND_ONLY_ROOTS);
3730}
3731
3732void LLSelectMgr::packPermissionsHead(void* user_data)
3733{
3734 LLPermData* data = (LLPermData*)user_data;
3735 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3736 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
3737 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3738 gMessageSystem->nextBlockFast(_PREHASH_HeaderData);
3739 gMessageSystem->addBOOLFast(_PREHASH_Override, data->mOverride);
3740}
3741
3742
3743// Now that you've added a bunch of objects, send a select message
3744// on the entire list for efficiency.
3745/*
3746void LLSelectMgr::sendSelect()
3747{
3748 llerrs << "Not implemented" << llendl;
3749}
3750*/
3751
3752void LLSelectMgr::deselectAll()
3753{
3754 if (!mSelectedObjects.getNumNodes())
3755 {
3756 return;
3757 }
3758
3759 sendListToRegions(
3760 "ObjectDeselect",
3761 packAgentAndSessionID,
3762 packObjectLocalID,
3763 NULL,
3764 SEND_INDIVIDUALS);
3765
3766 removeAll();
3767
3768 mLastSentSelectionCenterGlobal.clearVec();
3769
3770 updatePointAt();
3771 gHUDManager->clearJoints();
3772 updateSelectionCenter();
3773}
3774
3775void LLSelectMgr::deselectTransient()
3776{
3777 std::set<LLViewerObject*> objects_to_deselect;
3778 LLSelectNode *nodep;
3779 for (nodep = mSelectedObjects.getFirstNode(); nodep; nodep = mSelectedObjects.getNextNode())
3780 {
3781 if (nodep->isTransient())
3782 {
3783 objects_to_deselect.insert(nodep->getObject());
3784 }
3785 }
3786
3787 std::set<LLViewerObject*>::iterator iter;
3788 for (iter = objects_to_deselect.begin();
3789 iter != objects_to_deselect.end();
3790 ++iter)
3791 {
3792 deselectObjectOnly(*iter);
3793 }
3794
3795 gHUDManager->clearJoints();
3796 updateSelectionCenter();
3797}
3798
3799void LLSelectMgr::convertTransient()
3800{
3801 LLSelectNode *nodep;
3802 for (nodep = mSelectedObjects.getFirstNode(); nodep; nodep = mSelectedObjects.getNextNode())
3803 {
3804 nodep->setTransient(FALSE);
3805 }
3806}
3807
3808void LLSelectMgr::deselectAllIfTooFar()
3809{
3810 if (isEmpty() || mSelectType == SELECT_TYPE_HUD)
3811 {
3812 return;
3813 }
3814
3815 // HACK: Don't deselect when we're navigating to rate an object's
3816 // owner or creator. JC
3817 if (gPieObject->getVisible() || gPieRate->getVisible() )
3818 {
3819 return;
3820 }
3821
3822 LLVector3d selectionCenter = getSelectionCenterGlobal();
3823 if (gSavedSettings.getBOOL("LimitSelectDistance")
3824 && !selectionCenter.isExactlyZero())
3825 {
3826 F32 deselect_dist = gSavedSettings.getF32("MaxSelectDistance");
3827 F32 deselect_dist_sq = deselect_dist * deselect_dist;
3828
3829 LLVector3d select_delta = gAgent.getPositionGlobal() - selectionCenter;
3830 F32 select_dist_sq = (F32) select_delta.magVecSquared();
3831
3832 if (select_dist_sq > deselect_dist_sq)
3833 {
3834 if (gDebugSelectMgr)
3835 {
3836 llinfos << "Selection manager: auto-deselecting, select_dist = " << fsqrtf(select_dist_sq) << llendl;
3837 llinfos << "agent pos global = " << gAgent.getPositionGlobal() << llendl;
3838 llinfos << "selection pos global = " << selectionCenter << llendl;
3839 }
3840
3841 deselectAll();
3842 }
3843 }
3844}
3845
3846
3847void LLSelectMgr::setObjectName(const LLString& name)
3848{
3849 // we only work correctly if 1 object is selected.
3850 if(getRootObjectCount() == 1)
3851 {
3852 sendListToRegions("ObjectName",
3853 packAgentAndSessionID,
3854 packObjectName,
3855 (void*)name.c_str(),
3856 SEND_ONLY_ROOTS);
3857 }
3858 else if(getObjectCount() == 1)
3859 {
3860 sendListToRegions("ObjectName",
3861 packAgentAndSessionID,
3862 packObjectName,
3863 (void*)name.c_str(),
3864 SEND_INDIVIDUALS);
3865 }
3866}
3867
3868void LLSelectMgr::setObjectDescription(const LLString& desc)
3869{
3870 // we only work correctly if 1 object is selected.
3871 if(getRootObjectCount() == 1)
3872 {
3873 sendListToRegions("ObjectDescription",
3874 packAgentAndSessionID,
3875 packObjectDescription,
3876 (void*)desc.c_str(),
3877 SEND_ONLY_ROOTS);
3878 }
3879 else if(getObjectCount() == 1)
3880 {
3881 sendListToRegions("ObjectDescription",
3882 packAgentAndSessionID,
3883 packObjectDescription,
3884 (void*)desc.c_str(),
3885 SEND_INDIVIDUALS);
3886 }
3887}
3888
3889void LLSelectMgr::setObjectCategory(const LLCategory& category)
3890{
3891 // for now, we only want to be able to set one root category at
3892 // a time.
3893 if(getRootObjectCount() != 1) return;
3894 sendListToRegions("ObjectCategory",
3895 packAgentAndSessionID,
3896 packObjectCategory,
3897 (void*)(&category),
3898 SEND_ONLY_ROOTS);
3899}
3900
3901void LLSelectMgr::setObjectSaleInfo(const LLSaleInfo& sale_info)
3902{
3903 // Only one sale info at a time for now
3904 if(getRootObjectCount() != 1) return;
3905 sendListToRegions("ObjectSaleInfo",
3906 packAgentAndSessionID,
3907 packObjectSaleInfo,
3908 (void*)(&sale_info),
3909 SEND_ONLY_ROOTS);
3910}
3911
3912//----------------------------------------------------------------------
3913// Attachments
3914//----------------------------------------------------------------------
3915
3916void LLSelectMgr::sendAttach(U8 attachment_point)
3917{
3918 LLViewerObject* attach_object = mSelectedObjects.getFirstRootObject();
3919
3920 if (!attach_object || !gAgent.getAvatarObject() || mSelectType != SELECT_TYPE_WORLD)
3921 {
3922 return;
3923 }
3924
3925 BOOL build_mode = gToolMgr->inEdit();
3926 // Special case: Attach to default location for this object.
3927 if (0 == attachment_point)
3928 {
3929 sendListToRegions(
3930 "ObjectAttach",
3931 packAgentIDAndSessionAndAttachment,
3932 packObjectIDAndRotation,
3933 &attachment_point,
3934 SEND_ONLY_ROOTS );
3935 if (!build_mode)
3936 {
3937 deselectAll();
3938 }
3939 }
3940 else
3941 {
3942 LLViewerJointAttachment* attachment = gAgent.getAvatarObject()->mAttachmentPoints.getIfThere(attachment_point);
3943 if (attachment)
3944 {
3945 LLQuaternion object_world_rot = attach_object->getRenderRotation();
3946 LLQuaternion attachment_pt__world_rot = attachment->getWorldRotation();
3947 LLQuaternion local_rot = object_world_rot * ~attachment_pt__world_rot;
3948
3949 F32 x,y,z;
3950 local_rot.getEulerAngles(&x, &y, &z);
3951 // snap to nearest 90 degree rotation
3952 // make sure all euler angles are positive
3953 if (x < F_PI_BY_TWO) x += F_TWO_PI;
3954 if (y < F_PI_BY_TWO) y += F_TWO_PI;
3955 if (z < F_PI_BY_TWO) z += F_TWO_PI;
3956
3957 // add 45 degrees so that rounding down becomes rounding off
3958 x += F_PI_BY_TWO / 2.f;
3959 y += F_PI_BY_TWO / 2.f;
3960 z += F_PI_BY_TWO / 2.f;
3961 // round down to nearest multiple of 90 degrees
3962 x -= fmodf(x, F_PI_BY_TWO);
3963 y -= fmodf(y, F_PI_BY_TWO);
3964 z -= fmodf(z, F_PI_BY_TWO);
3965
3966 // pass the requested rotation on to the simulator
3967 local_rot.setQuat(x, y, z);
3968 attach_object->setRotation(local_rot);
3969
3970 sendListToRegions(
3971 "ObjectAttach",
3972 packAgentIDAndSessionAndAttachment,
3973 packObjectIDAndRotation,
3974 &attachment_point,
3975 SEND_ONLY_ROOTS );
3976 if (!build_mode)
3977 {
3978 deselectAll();
3979 }
3980 }
3981 }
3982}
3983
3984void LLSelectMgr::sendDetach()
3985{
3986 if (!mSelectedObjects.getNumNodes() || mSelectType == SELECT_TYPE_WORLD)
3987 {
3988 return;
3989 }
3990
3991 sendListToRegions(
3992 "ObjectDetach",
3993 packAgentAndSessionID,
3994 packObjectLocalID,
3995 NULL,
3996 SEND_ONLY_ROOTS );
3997}
3998
3999
4000void LLSelectMgr::sendDropAttachment()
4001{
4002 if (!mSelectedObjects.getNumNodes() || mSelectType == SELECT_TYPE_WORLD)
4003 {
4004 return;
4005 }
4006
4007 sendListToRegions(
4008 "ObjectDrop",
4009 packAgentAndSessionID,
4010 packObjectLocalID,
4011 NULL,
4012 SEND_ONLY_ROOTS);
4013}
4014
4015//----------------------------------------------------------------------
4016// Links
4017//----------------------------------------------------------------------
4018
4019void LLSelectMgr::sendLink()
4020{
4021 if (!mSelectedObjects.getNumNodes())
4022 {
4023 return;
4024 }
4025
4026 sendListToRegions(
4027 "ObjectLink",
4028 packAgentAndSessionID,
4029 packObjectLocalID,
4030 NULL,
4031 SEND_ONLY_ROOTS);
4032}
4033
4034void LLSelectMgr::sendDelink()
4035{
4036 if (!mSelectedObjects.getNumNodes())
4037 {
4038 return;
4039 }
4040
4041 // Delink needs to send individuals so you can unlink a single object from
4042 // a linked set.
4043 sendListToRegions(
4044 "ObjectDelink",
4045 packAgentAndSessionID,
4046 packObjectLocalID,
4047 NULL,
4048 SEND_INDIVIDUALS);
4049}
4050
4051
4052//----------------------------------------------------------------------
4053// Hinges
4054//----------------------------------------------------------------------
4055
4056void LLSelectMgr::sendHinge(U8 type)
4057{
4058 if (!mSelectedObjects.getNumNodes())
4059 {
4060 return;
4061 }
4062
4063 sendListToRegions(
4064 "ObjectHinge",
4065 packHingeHead,
4066 packObjectLocalID,
4067 &type,
4068 SEND_ONLY_ROOTS);
4069}
4070
4071
4072void LLSelectMgr::sendDehinge()
4073{
4074 if (!mSelectedObjects.getNumNodes())
4075 {
4076 return;
4077 }
4078
4079 sendListToRegions(
4080 "ObjectDehinge",
4081 packAgentAndSessionID,
4082 packObjectLocalID,
4083 NULL,
4084 SEND_ONLY_ROOTS);
4085}
4086
4087void LLSelectMgr::sendSelect()
4088{
4089 if (!mSelectedObjects.getNumNodes())
4090 {
4091 return;
4092 }
4093
4094 sendListToRegions(
4095 "ObjectSelect",
4096 packAgentAndSessionID,
4097 packObjectLocalID,
4098 NULL,
4099 SEND_INDIVIDUALS);
4100}
4101
4102// static
4103void LLSelectMgr::packHingeHead(void *user_data)
4104{
4105 U8 *type = (U8 *)user_data;
4106
4107 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4108 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4109 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
4110 gMessageSystem->nextBlockFast(_PREHASH_JointType);
4111 gMessageSystem->addU8Fast(_PREHASH_Type, *type );
4112}
4113
4114
4115void LLSelectMgr::selectionDump()
4116{
4117 LLViewerObject *object;
4118
4119 for (object = getFirstObject(); object; object = getNextObject() )
4120 {
4121 object->dump();
4122 }
4123}
4124
4125void LLSelectMgr::saveSelectedObjectColors()
4126{
4127 LLSelectNode* selectNode;
4128 for (selectNode = getFirstNode(); selectNode; selectNode = getNextNode() )
4129 {
4130 selectNode->saveColors();
4131 }
4132}
4133
4134void LLSelectMgr::saveSelectedObjectTextures()
4135{
4136 LLSelectNode* selectNode;
4137
4138 // invalidate current selection so we update saved textures
4139 for (selectNode = getFirstNode(); selectNode; selectNode = getNextNode() )
4140 {
4141 selectNode->mValid = FALSE;
4142 }
4143
4144 // request object properties message to get updated permissions data
4145 sendSelect();
4146}
4147
4148
4149// This routine should be called whenever a drag is initiated.
4150// also need to know to which simulator to send update message
4151void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type)
4152{
4153 LLSelectNode* selectNode;
4154
4155 if (isEmpty())
4156 {
4157 // nothing selected, so nothing to save
4158 return;
4159 }
4160
4161 for (selectNode = getFirstNode(); selectNode; selectNode = getNextNode() )
4162 {
4163 LLViewerObject* object;
4164 object = selectNode->getObject();
4165 selectNode->mSavedPositionLocal = object->getPosition();
4166 if (object->isAttachment())
4167 {
4168 if (object->isRootEdit())
4169 {
4170 LLXform* parent_xform = object->mDrawable->getXform()->getParent();
4171 selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition());
4172 }
4173 else
4174 {
4175 LLViewerObject* attachment_root = (LLViewerObject*)object->getParent();
4176 LLXform* parent_xform = attachment_root->mDrawable->getXform()->getParent();
4177 LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
4178 LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation());
4179 selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos);
4180 }
4181 selectNode->mSavedRotation = object->getRenderRotation();
4182 }
4183 else
4184 {
4185 selectNode->mSavedPositionGlobal = object->getPositionGlobal();
4186 selectNode->mSavedRotation = object->getRotationRegion();
4187 }
4188
4189 selectNode->mSavedScale = object->getScale();
4190 selectNode->saveTextureScaleRatios();
4191
4192 if (object->isAttachment() &&
4193 action_type != SELECT_ACTION_TYPE_PICK)
4194 {
4195 LLSelectAction* selectAction = new LLSelectAction();
4196 selectAction->mActionType = action_type;
4197 selectAction->mPosition = object->getPosition();
4198 selectAction->mRotation = object->getRotation();
4199 selectAction->mScale = object->getScale();
4200 selectAction->mObjectID = object->getID();
4201 selectAction->mIndividualSelection = selectNode->mIndividualSelection;
4202
4203 mUndoQueue.push_back(selectAction);
4204
4205 while ((mUndoQueue.size() > (U32)MAX_ACTION_QUEUE_SIZE))
4206 {
4207 LLSelectAction* action = mUndoQueue.front();
4208 mUndoQueue.pop_front();
4209 delete action;
4210 }
4211
4212 // remove this object from the redo queue
4213 std::deque<LLSelectAction*>::iterator it;
4214 for (it = mRedoQueue.begin(); it != mRedoQueue.end();)
4215 {
4216 if ((*it)->mObjectID == object->getID())
4217 {
4218 LLSelectAction* actionp = *it;
4219 it = mRedoQueue.erase(it);
4220 delete actionp;
4221 }
4222 else
4223 {
4224 ++it;
4225 }
4226 }
4227 }
4228 }
4229 mSavedSelectionBBox = getBBoxOfSelection();
4230}
4231
4232void LLSelectMgr::selectionUpdatePhysics(BOOL physics)
4233{
4234 LLViewerObject *object;
4235
4236 for (object = getFirstObject(); object; object = getNextObject() )
4237 {
4238 if ( !object->permModify() // preemptive permissions check
4239 || !(object->isRoot() // don't send for child objects
4240 || object->isJointChild()))
4241 {
4242 continue;
4243 }
4244 object->setFlags( FLAGS_USE_PHYSICS, physics);
4245 }
4246}
4247
4248void LLSelectMgr::selectionUpdateTemporary(BOOL is_temporary)
4249{
4250 LLViewerObject *object;
4251
4252 for (object = getFirstObject(); object; object = getNextObject() )
4253 {
4254 if ( !object->permModify() // preemptive permissions check
4255 || !(object->isRoot() // don't send for child objects
4256 || object->isJointChild()))
4257 {
4258 continue;
4259 }
4260 object->setFlags( FLAGS_TEMPORARY_ON_REZ, is_temporary);
4261 }
4262}
4263
4264void LLSelectMgr::selectionUpdatePhantom(BOOL is_phantom)
4265{
4266 LLViewerObject *object;
4267
4268 for (object = getFirstObject(); object; object = getNextObject() )
4269 {
4270 if ( !object->permModify() // preemptive permissions check
4271 || !(object->isRoot() // don't send for child objects
4272 || object->isJointChild()))
4273 {
4274 continue;
4275 }
4276 object->setFlags( FLAGS_PHANTOM, is_phantom);
4277 }
4278}
4279
4280void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows)
4281{
4282 LLViewerObject *object;
4283
4284 for (object = getFirstObject(); object; object = getNextObject() )
4285 {
4286 if ( !object->permModify() // preemptive permissions check
4287 || object->isJointChild())
4288 {
4289 continue;
4290 }
4291 object->setFlags( FLAGS_CAST_SHADOWS, cast_shadows);
4292 }
4293}
4294
4295
4296//----------------------------------------------------------------------
4297// Helpful packing functions for sendObjectMessage()
4298//----------------------------------------------------------------------
4299
4300// static
4301void LLSelectMgr::packAgentIDAndSessionAndAttachment( void *user_data)
4302{
4303 U8 *attachment_point = (U8*)user_data;
4304 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4305 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4306 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4307 gMessageSystem->addU8Fast(_PREHASH_AttachmentPoint, *attachment_point);
4308}
4309
4310// static
4311void LLSelectMgr::packAgentID( void *user_data)
4312{
4313 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4314 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4315}
4316
4317// static
4318void LLSelectMgr::packAgentAndSessionID(void* user_data)
4319{
4320 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4321 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4322 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4323}
4324
4325// static
4326void LLSelectMgr::packAgentAndGroupID(void* user_data)
4327{
4328 LLOwnerData *data = (LLOwnerData *)user_data;
4329
4330 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4331 gMessageSystem->addUUIDFast(_PREHASH_AgentID, data->owner_id );
4332 gMessageSystem->addUUIDFast(_PREHASH_GroupID, data->group_id );
4333}
4334
4335// static
4336void LLSelectMgr::packAgentAndSessionAndGroupID(void* user_data)
4337{
4338 LLUUID* group_idp = (LLUUID*) user_data;
4339 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4340 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4341 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4342 gMessageSystem->addUUIDFast(_PREHASH_GroupID, *group_idp);
4343}
4344
4345// static
4346void LLSelectMgr::packDuplicateHeader(void* data)
4347{
4348 LLUUID group_id(gAgent.getGroupID());
4349 packAgentAndSessionAndGroupID(&group_id);
4350
4351 LLDuplicateData* dup_data = (LLDuplicateData*) data;
4352
4353 gMessageSystem->nextBlockFast(_PREHASH_SharedData);
4354 gMessageSystem->addVector3Fast(_PREHASH_Offset, dup_data->offset);
4355 gMessageSystem->addU32Fast(_PREHASH_DuplicateFlags, dup_data->flags);
4356}
4357
4358// static
4359void LLSelectMgr::packDeleteHeader(void* userdata)
4360{
4361 BOOL force = (BOOL)(intptr_t)userdata;
4362
4363 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4364 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4365 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4366 gMessageSystem->addBOOLFast(_PREHASH_Force, force);
4367}
4368
4369// static
4370void LLSelectMgr::packAgentGroupAndCatID(void* user_data)
4371{
4372 LLBuyData* buy = (LLBuyData*)user_data;
4373 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4374 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4375 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4376 gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
4377 gMessageSystem->addUUIDFast(_PREHASH_CategoryID, buy->mCategoryID);
4378}
4379
4380//static
4381void LLSelectMgr::packDeRezHeader(void* user_data)
4382{
4383 LLDeRezInfo* info = (LLDeRezInfo*)user_data;
4384 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4385 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4386 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4387 gMessageSystem->nextBlockFast(_PREHASH_AgentBlock);
4388 gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
4389 gMessageSystem->addU8Fast(_PREHASH_Destination, (U8)info->mDestination);
4390 gMessageSystem->addUUIDFast(_PREHASH_DestinationID, info->mDestinationID);
4391 LLUUID tid;
4392 tid.generate();
4393 gMessageSystem->addUUIDFast(_PREHASH_TransactionID, tid);
4394 const U8 PACKET = 1;
4395 gMessageSystem->addU8Fast(_PREHASH_PacketCount, PACKET);
4396 gMessageSystem->addU8Fast(_PREHASH_PacketNumber, PACKET);
4397}
4398
4399// static
4400void LLSelectMgr::packObjectID(LLSelectNode* node, void *user_data)
4401{
4402 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4403 gMessageSystem->addUUIDFast(_PREHASH_ObjectID, node->getObject()->mID );
4404}
4405
4406void LLSelectMgr::packObjectIDAndRotation(LLSelectNode* node, void *user_data)
4407{
4408 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4409 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() );
4410 gMessageSystem->addQuatFast(_PREHASH_Rotation, node->getObject()->getRotation());
4411}
4412
4413void LLSelectMgr::packObjectClickAction(LLSelectNode* node, void *user_data)
4414{
4415 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4416 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID() );
4417 gMessageSystem->addU8("ClickAction", node->getObject()->getClickAction());
4418}
4419
4420// static
4421void LLSelectMgr::packObjectLocalID(LLSelectNode* node, void *)
4422{
4423 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4424 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID());
4425}
4426
4427// static
4428void LLSelectMgr::packObjectName(LLSelectNode* node, void* user_data)
4429{
4430 char* name = (char*)user_data;
4431 if(!name) return;
4432 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4433 gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
4434 gMessageSystem->addStringFast(_PREHASH_Name, name);
4435}
4436
4437// static
4438void LLSelectMgr::packObjectDescription(LLSelectNode* node,
4439 void* user_data)
4440{
4441 char* desc = (char*)user_data;
4442 if(!desc) return;
4443 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4444 gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
4445 gMessageSystem->addStringFast(_PREHASH_Description, desc);
4446}
4447
4448// static
4449void LLSelectMgr::packObjectCategory(LLSelectNode* node, void* user_data)
4450{
4451 LLCategory* category = (LLCategory*)user_data;
4452 if(!category) return;
4453 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4454 gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
4455 category->packMessage(gMessageSystem);
4456}
4457
4458// static
4459void LLSelectMgr::packObjectSaleInfo(LLSelectNode* node, void* user_data)
4460{
4461 LLSaleInfo* sale_info = (LLSaleInfo*)user_data;
4462 if(!sale_info) return;
4463 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4464 gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID());
4465 sale_info->packMessage(gMessageSystem);
4466}
4467
4468// static
4469void LLSelectMgr::packPhysics(LLSelectNode* node, void *user_data)
4470{
4471}
4472
4473// static
4474void LLSelectMgr::packShape(LLSelectNode* node, void *user_data)
4475{
4476}
4477
4478// static
4479void LLSelectMgr::packPermissions(LLSelectNode* node, void *user_data)
4480{
4481 LLPermData *data = (LLPermData *)user_data;
4482
4483 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4484 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, node->getObject()->getLocalID());
4485
4486 gMessageSystem->addU8Fast(_PREHASH_Field, data->mField);
4487 gMessageSystem->addBOOLFast(_PREHASH_Set, data->mSet);
4488 gMessageSystem->addU32Fast(_PREHASH_Mask, data->mMask);
4489}
4490
4491// Utility function to send some information to every region containing
4492// an object on the selection list. We want to do this to reduce the total
4493// number of packets sent by the viewer.
4494void LLSelectMgr::sendListToRegions(const LLString& message_name,
4495 void (*pack_header)(void *user_data),
4496 void (*pack_body)(LLSelectNode* node, void *user_data),
4497 void *user_data,
4498 ESendType send_type)
4499{
4500 LLSelectNode* node;
4501 LLViewerRegion* last_region;
4502 LLViewerRegion* current_region;
4503
4504 S32 objects_sent = 0;
4505 S32 packets_sent = 0;
4506 S32 objects_in_this_packet = 0;
4507
4508 std::queue<LLSelectNode*> nodes_to_send;
4509
4510 switch(send_type)
4511 {
4512 case SEND_ONLY_ROOTS:
4513 node = mSelectedObjects.getFirstRootNode();
4514 while(node)
4515 {
4516 nodes_to_send.push(node);
4517 node = mSelectedObjects.getNextRootNode();
4518 }
4519 break;
4520 case SEND_INDIVIDUALS:
4521 node = mSelectedObjects.getFirstNode();
4522 while(node)
4523 {
4524 nodes_to_send.push(node);
4525 node = mSelectedObjects.getNextNode();
4526 }
4527 break;
4528 case SEND_ROOTS_FIRST:
4529 // first roots...
4530 node = mSelectedObjects.getFirstNode();
4531 while(node)
4532 {
4533 if (node->getObject()->isRootEdit())
4534 {
4535 nodes_to_send.push(node);
4536 }
4537 node = mSelectedObjects.getNextNode();
4538 }
4539
4540 // then children...
4541 node = mSelectedObjects.getFirstNode();
4542 while(node)
4543 {
4544 if (!node->getObject()->isRootEdit())
4545 {
4546 nodes_to_send.push(node);
4547 }
4548 node = mSelectedObjects.getNextNode();
4549 }
4550 break;
4551 case SEND_CHILDREN_FIRST:
4552 // first children...
4553 node = mSelectedObjects.getFirstNode();
4554 while(node)
4555 {
4556 if (!node->getObject()->isRootEdit())
4557 {
4558 nodes_to_send.push(node);
4559 }
4560 node = mSelectedObjects.getNextNode();
4561 }
4562
4563 // ...then roots
4564 node = mSelectedObjects.getFirstNode();
4565 while(node)
4566 {
4567 if (node->getObject()->isRootEdit())
4568 {
4569 nodes_to_send.push(node);
4570 }
4571 node = mSelectedObjects.getNextNode();
4572 }
4573 break;
4574
4575 default:
4576 llerrs << "Bad send type " << send_type << " passed to SendListToRegions()" << llendl;
4577 }
4578
4579 // bail if nothing selected
4580 if (nodes_to_send.empty()) return;
4581
4582 node = nodes_to_send.front();
4583 nodes_to_send.pop();
4584
4585 // cache last region information
4586 current_region = node->getObject()->getRegion();
4587
4588 // Start duplicate message
4589 // CRO: this isn't
4590 gMessageSystem->newMessage(message_name.c_str());
4591 (*pack_header)(user_data);
4592
4593 // For each object
4594 while (node != NULL)
4595 {
4596 // remember the last region, look up the current one
4597 last_region = current_region;
4598 current_region = node->getObject()->getRegion();
4599
4600 // if to same simulator and message not too big
4601 if ((current_region == last_region)
4602 && (gMessageSystem->mCurrentSendTotal < MTUBYTES)
4603 && (objects_in_this_packet < MAX_OBJECTS_PER_PACKET))
4604 {
4605 // add another instance of the body of the data
4606 (*pack_body)(node, user_data);
4607 ++objects_sent;
4608 ++objects_in_this_packet;
4609
4610 // and on to the next object
4611 if(nodes_to_send.empty())
4612 {
4613 node = NULL;
4614 }
4615 else
4616 {
4617 node = nodes_to_send.front();
4618 nodes_to_send.pop();
4619 }
4620 }
4621 else
4622 {
4623 // otherwise send current message and start new one
4624 gMessageSystem->sendReliable( last_region->getHost());
4625 packets_sent++;
4626 objects_in_this_packet = 0;
4627
4628 gMessageSystem->newMessage(message_name.c_str());
4629 (*pack_header)(user_data);
4630
4631 // don't move to the next object, we still need to add the
4632 // body data.
4633 }
4634 }
4635
4636 // flush messages
4637 if (gMessageSystem->mCurrentSendTotal > 0)
4638 {
4639 gMessageSystem->sendReliable( current_region->getHost());
4640 packets_sent++;
4641 }
4642 else
4643 {
4644 gMessageSystem->clearMessage();
4645 }
4646
4647 // llinfos << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << llendl;
4648}
4649
4650
4651//
4652// Network communications
4653//
4654
4655void LLSelectMgr::requestObjectPropertiesFamily(LLViewerObject* object)
4656{
4657 LLMessageSystem* msg = gMessageSystem;
4658
4659 msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily);
4660 msg->nextBlockFast(_PREHASH_AgentData);
4661 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4662 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4663 msg->nextBlockFast(_PREHASH_ObjectData);
4664 msg->addU32Fast(_PREHASH_RequestFlags, 0x0 );
4665 msg->addUUIDFast(_PREHASH_ObjectID, object->mID );
4666
4667 LLViewerRegion* regionp = object->getRegion();
4668 msg->sendReliable( regionp->getHost() );
4669}
4670
4671
4672// static
4673void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data)
4674{
4675 S32 i;
4676 S32 count = msg->getNumberOfBlocksFast(_PREHASH_ObjectData);
4677 for (i = 0; i < count; i++)
4678 {
4679 LLUUID id;
4680 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, id, i);
4681
4682 LLUUID creator_id;
4683 LLUUID owner_id;
4684 LLUUID group_id;
4685 LLUUID last_owner_id;
4686 U64 creation_date;
4687 LLUUID extra_id;
4688 U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask;
4689 LLSaleInfo sale_info;
4690 LLCategory category;
4691 LLAggregatePermissions ag_perms;
4692 LLAggregatePermissions ag_texture_perms;
4693 LLAggregatePermissions ag_texture_perms_owner;
4694
4695 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_CreatorID, creator_id, i);
4696 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, i);
4697 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id, i);
4698 msg->getU64Fast(_PREHASH_ObjectData, _PREHASH_CreationDate, creation_date, i);
4699 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, base_mask, i);
4700 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, owner_mask, i);
4701 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_GroupMask, group_mask, i);
4702 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, everyone_mask, i);
4703 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, next_owner_mask, i);
4704 sale_info.unpackMultiMessage(msg, _PREHASH_ObjectData, i);
4705
4706 ag_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePerms, i);
4707 ag_texture_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTextures, i);
4708 ag_texture_perms_owner.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTexturesOwner, i);
4709 category.unpackMultiMessage(msg, _PREHASH_ObjectData, i);
4710
4711 S16 inv_serial = 0;
4712 msg->getS16Fast(_PREHASH_ObjectData, _PREHASH_InventorySerial, inv_serial, i);
4713
4714 LLUUID item_id;
4715 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ItemID, item_id, i);
4716 LLUUID folder_id;
4717 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FolderID, folder_id, i);
4718 LLUUID from_task_id;
4719 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FromTaskID, from_task_id, i);
4720
4721 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, last_owner_id, i);
4722
4723 char name[DB_INV_ITEM_NAME_BUF_SIZE];
4724 msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name, i);
4725 char desc[DB_INV_ITEM_DESC_BUF_SIZE];
4726 msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, DB_INV_ITEM_DESC_BUF_SIZE, desc, i);
4727
4728 char touch_name[DB_INV_ITEM_NAME_BUF_SIZE];
4729 msg->getStringFast(_PREHASH_ObjectData, _PREHASH_TouchName, DB_INV_ITEM_NAME_BUF_SIZE, touch_name, i);
4730 char sit_name[DB_INV_ITEM_DESC_BUF_SIZE];
4731 msg->getStringFast(_PREHASH_ObjectData, _PREHASH_SitName, DB_INV_ITEM_DESC_BUF_SIZE, sit_name, i);
4732
4733 //unpack TE IDs
4734 std::vector<LLUUID> texture_ids;
4735 S32 size = msg->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_TextureID);
4736 if (size > 0)
4737 {
4738 S8 packed_buffer[SELECT_MAX_TES * UUID_BYTES];
4739 msg->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureID, packed_buffer, 0, i, SELECT_MAX_TES * UUID_BYTES);
4740
4741 for (S32 buf_offset = 0; buf_offset < size; buf_offset += UUID_BYTES)
4742 {
4743 LLUUID id;
4744 memcpy(id.mData, packed_buffer + buf_offset, UUID_BYTES);
4745 texture_ids.push_back(id);
4746 }
4747 }
4748
4749
4750 // Iterate through nodes at end, since it can be on both the regular AND hover list
4751 BOOL found = FALSE;
4752 LLSelectNode* node;
4753 for (node = gSelectMgr->mSelectedObjects.getFirstNode();
4754 node;
4755 node = gSelectMgr->mSelectedObjects.getNextNode())
4756 {
4757 if (node->getObject()->mID == id)
4758 {
4759 found = TRUE;
4760 break;
4761 }
4762 }
4763
4764
4765 if (node)
4766 {
4767 if (node->mInventorySerial != inv_serial)
4768 {
4769 node->getObject()->dirtyInventory();
4770 }
4771
4772 // save texture data as soon as we get texture perms first time
4773 if (!node->mValid)
4774 {
4775 BOOL can_copy = FALSE;
4776 BOOL can_transfer = FALSE;
4777
4778 LLAggregatePermissions::EValue value = LLAggregatePermissions::AP_NONE;
4779 if(node->getObject()->permYouOwner())
4780 {
4781 value = ag_texture_perms_owner.getValue(PERM_COPY);
4782 if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
4783 {
4784 can_copy = TRUE;
4785 }
4786 value = ag_texture_perms_owner.getValue(PERM_TRANSFER);
4787 if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
4788 {
4789 can_transfer = TRUE;
4790 }
4791 }
4792 else
4793 {
4794 value = ag_texture_perms.getValue(PERM_COPY);
4795 if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
4796 {
4797 can_copy = TRUE;
4798 }
4799 value = ag_texture_perms.getValue(PERM_TRANSFER);
4800 if (value == LLAggregatePermissions::AP_EMPTY || value == LLAggregatePermissions::AP_ALL)
4801 {
4802 can_transfer = TRUE;
4803 }
4804 }
4805
4806 if (can_copy && can_transfer)
4807 {
4808 // this should be the only place that saved textures is called
4809 node->saveTextures(texture_ids);
4810 }
4811 }
4812
4813 node->mValid = TRUE;
4814 node->mPermissions->init(creator_id, owner_id,
4815 last_owner_id, group_id);
4816 node->mPermissions->initMasks(base_mask, owner_mask, everyone_mask, group_mask, next_owner_mask);
4817 node->mCreationDate = creation_date;
4818 node->mItemID = item_id;
4819 node->mFolderID = folder_id;
4820 node->mFromTaskID = from_task_id;
4821 node->mName.assign(name);
4822 node->mDescription.assign(desc);
4823 node->mSaleInfo = sale_info;
4824 node->mAggregatePerm = ag_perms;
4825 node->mAggregateTexturePerm = ag_texture_perms;
4826 node->mAggregateTexturePermOwner = ag_texture_perms_owner;
4827 node->mCategory = category;
4828 node->mInventorySerial = inv_serial;
4829 node->mSitName.assign(sit_name);
4830 node->mTouchName.assign(touch_name);
4831 }
4832 }
4833
4834 dialog_refresh_all();
4835
4836 // silly hack to allow 'save into inventory'
4837 if(gPopupMenuView->getVisible())
4838 {
4839 gPopupMenuView->setItemEnabled(SAVE_INTO_INVENTORY,
4840 enable_save_into_inventory(NULL));
4841 }
4842
4843 // hack for left-click buy object
4844 LLToolPie::selectionPropertiesReceived();
4845}
4846
4847// static
4848void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** user_data)
4849{
4850 LLUUID id;
4851
4852 U32 request_flags;
4853 LLUUID creator_id;
4854 LLUUID owner_id;
4855 LLUUID group_id;
4856 LLUUID extra_id;
4857 U32 base_mask, owner_mask, group_mask, everyone_mask, next_owner_mask;
4858 LLSaleInfo sale_info;
4859 LLCategory category;
4860
4861 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_RequestFlags, request_flags );
4862 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, id );
4863 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id );
4864 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id );
4865 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, base_mask );
4866 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, owner_mask );
4867 msg->getU32Fast(_PREHASH_ObjectData,_PREHASH_GroupMask, group_mask );
4868 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, everyone_mask );
4869 msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, next_owner_mask);
4870 sale_info.unpackMessage(msg, _PREHASH_ObjectData);
4871 category.unpackMessage(msg, _PREHASH_ObjectData);
4872
4873 LLUUID last_owner_id;
4874 msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, last_owner_id );
4875
4876 // unpack name & desc
4877 char name[DB_INV_ITEM_NAME_BUF_SIZE];
4878 msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, DB_INV_ITEM_NAME_BUF_SIZE, name);
4879
4880 char desc[DB_INV_ITEM_DESC_BUF_SIZE];
4881 msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, DB_INV_ITEM_DESC_BUF_SIZE, desc);
4882
4883 // the reporter widget askes the server for info about picked objects
4884 if (request_flags & (COMPLAINT_REPORT_REQUEST | BUG_REPORT_REQUEST))
4885 {
4886 EReportType report_type = (COMPLAINT_REPORT_REQUEST & request_flags) ? COMPLAINT_REPORT : BUG_REPORT;
4887 LLFloaterReporter *reporterp = LLFloaterReporter::getReporter(report_type);
4888 if (reporterp)
4889 {
4890 char first_name[DB_FIRST_NAME_BUF_SIZE];
4891 char last_name[DB_LAST_NAME_BUF_SIZE];
4892 gCacheName->getName(owner_id, first_name, last_name);
4893 LLString fullname(first_name);
4894 fullname.append(" ");
4895 fullname.append(last_name);
4896 reporterp->setPickedObjectProperties(name, fullname.c_str());
4897 }
4898 }
4899
4900 // Now look through all of the hovered nodes
4901 BOOL found = FALSE;
4902 LLSelectNode* node;
4903 for (node = gSelectMgr->mHoverObjects.getFirstNode();
4904 node;
4905 node = gSelectMgr->mHoverObjects.getNextNode())
4906 {
4907 if (node->getObject()->mID == id)
4908 {
4909 found = TRUE;
4910 break;
4911 }
4912 }
4913
4914 if (node)
4915 {
4916 node->mValid = TRUE;
4917 node->mPermissions->init(LLUUID::null, owner_id,
4918 last_owner_id, group_id);
4919 node->mPermissions->initMasks(base_mask, owner_mask, everyone_mask, group_mask, next_owner_mask);
4920 node->mSaleInfo = sale_info;
4921 node->mCategory = category;
4922 node->mName.assign(name);
4923 node->mDescription.assign(desc);
4924 }
4925
4926 dialog_refresh_all();
4927}
4928
4929
4930// static
4931void LLSelectMgr::processForceObjectSelect(LLMessageSystem* msg, void**)
4932{
4933 BOOL reset_list;
4934 msg->getBOOL("Header", "ResetList", reset_list);
4935
4936 if (reset_list)
4937 {
4938 gSelectMgr->deselectAll();
4939 }
4940
4941 LLUUID full_id;
4942 S32 local_id;
4943 LLViewerObject* object;
4944 LLDynamicArray<LLViewerObject*> objects;
4945 S32 i;
4946 S32 block_count = msg->getNumberOfBlocks("Data");
4947
4948 for (i = 0; i < block_count; i++)
4949 {
4950 msg->getS32("Data", "LocalID", local_id, i);
4951
4952 gObjectList.getUUIDFromLocal(full_id,
4953 local_id,
4954 msg->getSenderIP(),
4955 msg->getSenderPort());
4956 object = gObjectList.findObject(full_id);
4957 if (object)
4958 {
4959 objects.put(object);
4960 }
4961 }
4962
4963 // Don't select, just highlight
4964 gSelectMgr->highlightObjectAndFamily(objects);
4965}
4966
4967
4968extern LLGLdouble gGLModelView[16];
4969
4970void LLSelectMgr::updateSilhouettes()
4971{
4972 LLSelectNode *node;
4973 S32 num_sils_genned = 0;
4974
4975 LLVector3d cameraPos = gAgent.getCameraPositionGlobal();
4976 F32 currentCameraZoom = gAgent.getCurrentCameraBuildOffset();
4977
4978 if (!mSilhouetteImagep)
4979 {
4980 LLUUID id;
4981 id.set( gViewerArt.getString("silhouette.tga") );
4982 mSilhouetteImagep = gImageList.getImage(id, TRUE, TRUE);
4983 }
4984
4985
4986 if((cameraPos - mLastCameraPos).magVecSquared() > SILHOUETTE_UPDATE_THRESHOLD_SQUARED * currentCameraZoom * currentCameraZoom)
4987 {
4988 for (node = mSelectedObjects.getFirstNode(); node; node = mSelectedObjects.getNextNode() )
4989 {
4990 if (node->getObject())
4991 {
4992 node->getObject()->setChanged(LLXform::SILHOUETTE);
4993 }
4994 }
4995
4996 mLastCameraPos = gAgent.getCameraPositionGlobal();
4997 }
4998
4999 LLDynamicArray<LLViewerObject*> changed_objects;
5000
5001 if (mSelectedObjects.getNumNodes())
5002 {
5003 //gGLSPipelineSelection.set();
5004
5005 //mSilhouetteImagep->bindTexture();
5006 //glAlphaFunc(GL_GREATER, sHighlightAlphaTest);
5007
5008 for (S32 pass = 0; pass < 2; pass++)
5009 {
5010 for (node = mSelectedObjects.getFirstNode(); node; node = mSelectedObjects.getNextNode() )
5011 {
5012 LLViewerObject* objectp = node->getObject();
5013
5014 // do roots first, then children so that root flags are cleared ASAP
5015 BOOL roots_only = (pass == 0);
5016 BOOL is_root = (objectp->isRootEdit());
5017 if (roots_only != is_root || objectp->mDrawable.isNull())
5018 {
5019 continue;
5020 }
5021
5022 if (!node->mSilhouetteExists
5023 || objectp->isChanged(LLXform::SILHOUETTE)
5024 || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE)))
5025 {
5026 if (num_sils_genned++ < MAX_SILS_PER_FRAME && objectp->mDrawable->isVisible())
5027 {
5028 generateSilhouette(node, gCamera->getOrigin());
5029 changed_objects.put(objectp);
5030 }
5031 else if (objectp->isAttachment())
5032 {
5033 //RN: hack for orthogonal projection of HUD attachments
5034 LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent();
5035 if (attachment_pt && attachment_pt->getIsHUDAttachment())
5036 {
5037 LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f);
5038 generateSilhouette(node, camera_pos);
5039 }
5040 }
5041 }
5042 }
5043 }
5044 }
5045
5046 if (mRectSelectedObjects.size() > 0)
5047 {
5048 //gGLSPipelineSelection.set();
5049
5050 //mSilhouetteImagep->bindTexture();
5051 //glAlphaFunc(GL_GREATER, sHighlightAlphaTest);
5052
5053 std::set<LLViewerObject*> roots;
5054
5055 // sync mHighlightedObjects with mRectSelectedObjects since the latter is rebuilt every frame and former
5056 // persists from frame to frame to avoid regenerating object silhouettes
5057 // mHighlightedObjects includes all siblings of rect selected objects
5058
5059 BOOL select_linked_set = gSavedSettings.getBOOL("SelectLinkedSet");
5060
5061 // generate list of roots from current object selection
5062 for (std::set<LLPointer<LLViewerObject> >::iterator iter = mRectSelectedObjects.begin();
5063 iter != mRectSelectedObjects.end(); iter++)
5064 {
5065 LLViewerObject *objectp = *iter;
5066 if (select_linked_set)
5067 {
5068 LLViewerObject *rootp = (LLViewerObject*)objectp->getRoot();
5069 roots.insert(rootp);
5070 }
5071 else
5072 {
5073 roots.insert(objectp);
5074 }
5075 }
5076
5077 // remove highlight nodes not in roots list
5078 LLDynamicArray<LLSelectNode*> remove_these_nodes;
5079 LLDynamicArray<LLViewerObject*> remove_these_roots;
5080 for (LLSelectNode* nodep = mHighlightedObjects.getFirstNode(); nodep; nodep = mHighlightedObjects.getNextNode())
5081 {
5082 LLViewerObject* objectp = nodep->getObject();
5083 if (objectp->isRoot() || !select_linked_set)
5084 {
5085 if (roots.count(objectp) == 0)
5086 {
5087 remove_these_nodes.put(nodep);
5088 }
5089 else
5090 {
5091 remove_these_roots.put(objectp);
5092 }
5093 }
5094 else
5095 {
5096 LLViewerObject* rootp = (LLViewerObject*)objectp->getRoot();
5097
5098 if (roots.count(rootp) == 0)
5099 {
5100 remove_these_nodes.put(nodep);
5101 }
5102 }
5103 }
5104
5105 // remove all highlight nodes no longer in rectangle selection
5106 S32 i;
5107 for (i = 0; i < remove_these_nodes.count(); i++)
5108 {
5109 mHighlightedObjects.removeNode(remove_these_nodes[i]);
5110 }
5111
5112 // remove all root objects already being highlighted
5113 for (i = 0; i < remove_these_roots.count(); i++)
5114 {
5115 roots.erase(remove_these_roots[i]);
5116 }
5117
5118 // add all new objects in rectangle selection
5119 for (std::set<LLViewerObject*>::iterator iter = roots.begin();
5120 iter != roots.end(); iter++)
5121 {
5122 LLViewerObject* objectp = *iter;
5123 LLSelectNode* rect_select_node = new LLSelectNode(objectp, TRUE);
5124 rect_select_node->selectAllTEs(TRUE);
5125
5126 if (!canSelectObject(objectp))
5127 {
5128 continue;
5129 }
5130
5131 mHighlightedObjects.addNode(rect_select_node);
5132
5133 if (!select_linked_set)
5134 {
5135 rect_select_node->mIndividualSelection = TRUE;
5136 }
5137 else
5138 {
5139 for (U32 i = 0; i < objectp->mChildList.size(); i++)
5140 {
5141 LLViewerObject* child_objectp = objectp->mChildList[i];
5142
5143 if (!canSelectObject(child_objectp))
5144 {
5145 continue;
5146 }
5147
5148 rect_select_node = new LLSelectNode(objectp->mChildList[i], TRUE);
5149 rect_select_node->selectAllTEs(TRUE);
5150 mHighlightedObjects.addNode(rect_select_node);
5151 }
5152 }
5153 }
5154
5155 num_sils_genned = 0;
5156
5157 // render silhouettes for highlighted objects
5158 //BOOL subtracting_from_selection = (gKeyboard->currentMask(TRUE) == MASK_CONTROL);
5159 for (S32 pass = 0; pass < 2; pass++)
5160 {
5161 for (node = mHighlightedObjects.getFirstNode(); node; node = mHighlightedObjects.getNextNode() )
5162 {
5163 LLViewerObject* objectp = node->getObject();
5164
5165 // do roots first, then children so that root flags are cleared ASAP
5166 BOOL roots_only = (pass == 0);
5167 BOOL is_root = objectp->isRootEdit();
5168 if (roots_only != is_root)
5169 {
5170 continue;
5171 }
5172
5173 if (!node->mSilhouetteExists
5174 || objectp->isChanged(LLXform::SILHOUETTE)
5175 || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE)))
5176 {
5177 if (num_sils_genned++ < MAX_SILS_PER_FRAME)
5178 {
5179 generateSilhouette(node, gCamera->getOrigin());
5180 changed_objects.put(objectp);
5181 }
5182 else if (objectp->isAttachment() && objectp->getRootEdit()->mDrawable.notNull())
5183 {
5184 //RN: hack for orthogonal projection of HUD attachments
5185 LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent();
5186 if (attachment_pt && attachment_pt->getIsHUDAttachment())
5187 {
5188 LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f);
5189 generateSilhouette(node, camera_pos);
5190 }
5191 }
5192 }
5193 //LLColor4 highlight_color;
5194 //
5195 //if (subtracting_from_selection)
5196 //{
5197 // node->renderOneSilhouette(LLColor4::red);
5198 //}
5199 //else if (!objectp->isSelected())
5200 //{
5201 // highlight_color = objectp->isRoot() ? sHighlightParentColor : sHighlightChildColor;
5202 // node->renderOneSilhouette(highlight_color);
5203 //}
5204 }
5205 }
5206 //mSilhouetteImagep->unbindTexture(0, GL_TEXTURE_2D);
5207 }
5208 else
5209 {
5210 mHighlightedObjects.deleteAllNodes();
5211 }
5212
5213 for (S32 i = 0; i < changed_objects.count(); i++)
5214 {
5215 // clear flags after traversing node list (as child objects need to refer to parent flags, etc)
5216 changed_objects[i]->clearChanged(LLXform::MOVED | LLXform::SILHOUETTE);
5217 }
5218
5219 //glAlphaFunc(GL_GREATER, 0.01f);
5220}
5221
5222void LLSelectMgr::renderSilhouettes(BOOL for_hud)
5223{
5224 if (!mRenderSilhouettes)
5225 {
5226 return;
5227 }
5228
5229 LLSelectNode *node;
5230 LLViewerImage::bindTexture(gSelectMgr->mSilhouetteImagep);
5231 LLGLSPipelineSelection gls_select;
5232 glAlphaFunc(GL_GREATER, 0.0f);
5233 LLGLEnable blend(GL_BLEND);
5234 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
5235
5236 LLVOAvatar* avatar = gAgent.getAvatarObject();
5237 if (for_hud && avatar)
5238 {
5239 LLBBox hud_bbox = avatar->getHUDBBox();
5240
5241 F32 cur_zoom = avatar->mHUDCurZoom;
5242
5243 // set up transform to encompass bounding box of HUD
5244 glMatrixMode(GL_PROJECTION);
5245 glPushMatrix();
5246 glLoadIdentity();
5247 F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
5248 glOrtho(-0.5f * gCamera->getAspect(), 0.5f * gCamera->getAspect(), -0.5f, 0.5f, 0.f, depth);
5249
5250 glMatrixMode(GL_MODELVIEW);
5251 glPushMatrix();
5252 glLoadIdentity();
5253 glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
5254 glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
5255 glScalef(cur_zoom, cur_zoom, cur_zoom);
5256 }
5257 if (mSelectedObjects.getNumNodes())
5258 {
5259 glPushAttrib(GL_FOG_BIT);
5260 LLUUID inspect_item_id = LLFloaterInspect::getSelectedUUID();
5261 for (S32 pass = 0; pass < 2; pass++)
5262 {
5263 for (node = mSelectedObjects.getFirstNode(); node; node = mSelectedObjects.getNextNode() )
5264 {
5265 LLViewerObject* objectp = node->getObject();
5266 if (objectp->isHUDAttachment() != for_hud)
5267 {
5268 continue;
5269 }
5270 if(objectp->getID() == inspect_item_id)
5271 {
5272 node->renderOneSilhouette(sHighlightInspectColor);
5273 }
5274 else if (node->isTransient())
5275 {
5276 BOOL oldHidden = LLSelectMgr::sRenderHiddenSelections;
5277 LLSelectMgr::sRenderHiddenSelections = FALSE;
5278 node->renderOneSilhouette(sContextSilhouetteColor);
5279 LLSelectMgr::sRenderHiddenSelections = oldHidden;
5280 }
5281 else if (objectp->isRootEdit())
5282 {
5283 node->renderOneSilhouette(sSilhouetteParentColor);
5284 }
5285 else
5286 {
5287 node->renderOneSilhouette(sSilhouetteChildColor);
5288 }
5289 }
5290 }
5291 glPopAttrib();
5292 }
5293
5294 if (mHighlightedObjects.getNumNodes())
5295 {
5296 // render silhouettes for highlighted objects
5297 BOOL subtracting_from_selection = (gKeyboard->currentMask(TRUE) == MASK_CONTROL);
5298 for (S32 pass = 0; pass < 2; pass++)
5299 {
5300 for (node = mHighlightedObjects.getFirstNode(); node; node = mHighlightedObjects.getNextNode() )
5301 {
5302 LLViewerObject* objectp = node->getObject();
5303 if (objectp->isHUDAttachment() != for_hud)
5304 {
5305 continue;
5306 }
5307
5308 if (subtracting_from_selection)
5309 {
5310 node->renderOneSilhouette(LLColor4::red);
5311 }
5312 else if (!objectp->isSelected())
5313 {
5314 LLColor4 highlight_color = objectp->isRoot() ? sHighlightParentColor : sHighlightChildColor;
5315 node->renderOneSilhouette(highlight_color);
5316 }
5317 }
5318 }
5319 }
5320
5321 if (for_hud && avatar)
5322 {
5323 glMatrixMode(GL_PROJECTION);
5324 glPopMatrix();
5325
5326 glMatrixMode(GL_MODELVIEW);
5327 glPopMatrix();
5328 stop_glerror();
5329 }
5330
5331 gSelectMgr->mSilhouetteImagep->unbindTexture(0, GL_TEXTURE_2D);
5332 glAlphaFunc(GL_GREATER, 0.01f);
5333}
5334
5335void LLSelectMgr::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
5336{
5337 LLViewerObject* objectp = nodep->getObject();
5338
5339 if (objectp && objectp->getPCode() == LL_PCODE_VOLUME)
5340 {
5341 ((LLVOVolume*)objectp)->generateSilhouette(nodep, view_point);
5342 }
5343}
5344
5345void LLSelectMgr::getSilhouetteExtents(LLSelectNode* nodep, const LLQuaternion& orientation, LLVector3& min_extents, LLVector3& max_extents)
5346{
5347 LLViewerObject* objectp = nodep->getObject();
5348
5349 if (objectp->mDrawable.isNull())
5350 {
5351 return;
5352 }
5353
5354 LLQuaternion test_rot = orientation * ~objectp->getRenderRotation();
5355 LLVector3 x_axis_rot = LLVector3::x_axis * test_rot;
5356 LLVector3 y_axis_rot = LLVector3::y_axis * test_rot;
5357 LLVector3 z_axis_rot = LLVector3::z_axis * test_rot;
5358
5359 x_axis_rot.scaleVec(objectp->mDrawable->getScale());
5360 y_axis_rot.scaleVec(objectp->mDrawable->getScale());
5361 z_axis_rot.scaleVec(objectp->mDrawable->getScale());
5362
5363 generateSilhouette(nodep, objectp->mDrawable->getPositionAgent() + x_axis_rot * 100.f);
5364
5365 S32 num_vertices = nodep->mSilhouetteVertices.size();
5366 if (num_vertices)
5367 {
5368 min_extents.mV[VY] = llmin(min_extents.mV[VY], nodep->mSilhouetteVertices[0] * y_axis_rot);
5369 max_extents.mV[VY] = llmax(max_extents.mV[VY], nodep->mSilhouetteVertices[0] * y_axis_rot);
5370
5371 min_extents.mV[VZ] = llmin(min_extents.mV[VZ], nodep->mSilhouetteVertices[0] * z_axis_rot);
5372 max_extents.mV[VZ] = llmax(min_extents.mV[VZ], nodep->mSilhouetteVertices[0] * z_axis_rot);
5373
5374 for (S32 vert = 1; vert < num_vertices; vert++)
5375 {
5376 F32 y_pos = nodep->mSilhouetteVertices[vert] * y_axis_rot;
5377 F32 z_pos = nodep->mSilhouetteVertices[vert] * z_axis_rot;
5378 min_extents.mV[VY] = llmin(y_pos, min_extents.mV[VY]);
5379 max_extents.mV[VY] = llmax(y_pos, max_extents.mV[VY]);
5380 min_extents.mV[VZ] = llmin(z_pos, min_extents.mV[VZ]);
5381 max_extents.mV[VZ] = llmax(z_pos, max_extents.mV[VZ]);
5382 }
5383 }
5384
5385 generateSilhouette(nodep, objectp->mDrawable->getPositionAgent() + y_axis_rot * 100.f);
5386
5387 num_vertices = nodep->mSilhouetteVertices.size();
5388 if (num_vertices)
5389 {
5390 min_extents.mV[VX] = llmin(min_extents.mV[VX], nodep->mSilhouetteVertices[0] * x_axis_rot);
5391 max_extents.mV[VX] = llmax(max_extents.mV[VX], nodep->mSilhouetteVertices[0] * x_axis_rot);
5392
5393 for (S32 vert = 1; vert < num_vertices; vert++)
5394 {
5395 F32 x_pos = nodep->mSilhouetteVertices[vert] * x_axis_rot;
5396 min_extents.mV[VX] = llmin(x_pos, min_extents.mV[VX]);
5397 max_extents.mV[VX] = llmax(x_pos, max_extents.mV[VX]);
5398 }
5399 }
5400
5401 generateSilhouette(nodep, gCamera->getOrigin());
5402}
5403
5404
5405//
5406// Utility classes
5407//
5408LLSelectNode::LLSelectNode(LLViewerObject* object, BOOL glow)
5409{
5410 mObject = object;
5411 selectAllTEs(FALSE);
5412 mIndividualSelection = FALSE;
5413 mTransient = FALSE;
5414 mValid = FALSE;
5415 mPermissions = new LLPermissions();
5416 mInventorySerial = 0;
5417 mName = LLString::null;
5418 mDescription = LLString::null;
5419 mTouchName = LLString::null;
5420 mSitName = LLString::null;
5421 mSilhouetteExists = FALSE;
5422 mDuplicated = FALSE;
5423
5424 saveColors();
5425}
5426
5427LLSelectNode::LLSelectNode(const LLSelectNode& nodep)
5428{
5429 S32 i;
5430 for (i = 0; i < SELECT_MAX_TES; i++)
5431 {
5432 mTESelected[i] = nodep.mTESelected[i];
5433 }
5434 mLastTESelected = nodep.mLastTESelected;
5435
5436 mIndividualSelection = nodep.mIndividualSelection;
5437
5438 mValid = nodep.mValid;
5439 mTransient = nodep.mTransient;
5440 mPermissions = new LLPermissions(*nodep.mPermissions);
5441 mSaleInfo = nodep.mSaleInfo;;
5442 mAggregatePerm = nodep.mAggregatePerm;
5443 mAggregateTexturePerm = nodep.mAggregateTexturePerm;
5444 mAggregateTexturePermOwner = nodep.mAggregateTexturePermOwner;
5445 mName = nodep.mName;
5446 mDescription = nodep.mDescription;
5447 mCategory = nodep.mCategory;
5448 mSavedPositionLocal = nodep.mSavedPositionLocal;
5449 mSavedPositionGlobal = nodep.mSavedPositionGlobal;
5450 mSavedScale = nodep.mSavedScale;
5451 mSavedRotation = nodep.mSavedRotation;
5452 mDuplicated = nodep.mDuplicated;
5453 mDuplicatePos = nodep.mDuplicatePos;
5454 mDuplicateRot = nodep.mDuplicateRot;
5455 mItemID = nodep.mItemID;
5456 mFolderID = nodep.mFolderID;
5457 mFromTaskID = nodep.mFromTaskID;
5458 mTouchName = nodep.mTouchName;
5459 mSitName = nodep.mSitName;
5460
5461 mSilhouetteVertices = nodep.mSilhouetteVertices;
5462 mSilhouetteNormals = nodep.mSilhouetteNormals;
5463 mSilhouetteSegments = nodep.mSilhouetteSegments;
5464 mSilhouetteExists = nodep.mSilhouetteExists;
5465 mObject = nodep.mObject;
5466
5467 std::vector<LLColor4>::const_iterator color_iter;
5468 mSavedColors.clear();
5469 for (color_iter = nodep.mSavedColors.begin(); color_iter != nodep.mSavedColors.end(); ++color_iter)
5470 {
5471 mSavedColors.push_back(*color_iter);
5472 }
5473
5474 saveTextures(nodep.mSavedTextures);
5475}
5476
5477LLSelectNode::~LLSelectNode()
5478{
5479 delete mPermissions;
5480 mPermissions = NULL;
5481}
5482
5483void LLSelectNode::selectAllTEs(BOOL b)
5484{
5485 for (S32 i = 0; i < SELECT_MAX_TES; i++)
5486 {
5487 mTESelected[i] = b;
5488 }
5489 mLastTESelected = 0;
5490}
5491
5492void LLSelectNode::selectTE(S32 te_index, BOOL selected)
5493{
5494 if (te_index < 0 || te_index >= SELECT_MAX_TES)
5495 {
5496 return;
5497 }
5498 mTESelected[te_index] = selected;
5499 mLastTESelected = te_index;
5500}
5501
5502BOOL LLSelectNode::isTESelected(S32 te_index)
5503{
5504 if (te_index < 0 || te_index >= mObject->getNumTEs())
5505 {
5506 return FALSE;
5507 }
5508 return mTESelected[te_index];
5509}
5510
5511S32 LLSelectNode::getLastSelectedTE()
5512{
5513 if (!isTESelected(mLastTESelected))
5514 {
5515 return -1;
5516 }
5517 return mLastTESelected;
5518}
5519
5520LLViewerObject *LLSelectNode::getObject()
5521{
5522 if (!mObject)
5523 {
5524 return NULL;
5525 }
5526 else if (mObject->isDead())
5527 {
5528 mObject = NULL;
5529 }
5530 return mObject;
5531}
5532
5533void LLSelectNode::saveColors()
5534{
5535 if (mObject.notNull())
5536 {
5537 mSavedColors.clear();
5538 for (S32 i = 0; i < mObject->getNumTEs(); i++)
5539 {
5540 const LLTextureEntry* tep = mObject->getTE(i);
5541 mSavedColors.push_back(tep->getColor());
5542 }
5543 }
5544}
5545
5546void LLSelectNode::saveTextures(const std::vector<LLUUID>& textures)
5547{
5548 if (mObject.notNull())
5549 {
5550 mSavedTextures.clear();
5551
5552 std::vector<LLUUID>::const_iterator texture_it;
5553 for (texture_it = textures.begin(); texture_it != textures.end(); ++texture_it)
5554 {
5555 mSavedTextures.push_back(*texture_it);
5556 }
5557 }
5558}
5559
5560void LLSelectNode::saveTextureScaleRatios()
5561{
5562 mTextureScaleRatios.clear();
5563 if (mObject.notNull())
5564 {
5565 for (U8 i = 0; i < mObject->getNumTEs(); i++)
5566 {
5567 F32 s,t;
5568 const LLTextureEntry* tep = mObject->getTE(i);
5569 tep->getScale(&s,&t);
5570 U32 s_axis, t_axis;
5571
5572 gSelectMgr->getTESTAxes(mObject, i, &s_axis, &t_axis);
5573
5574 LLVector3 v;
5575 LLVector3 scale = mObject->getScale();
5576
5577 if (tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR)
5578 {
5579 v.mV[s_axis] = s*scale.mV[s_axis];
5580 v.mV[t_axis] = t*scale.mV[t_axis];
5581 }
5582 else
5583 {
5584 v.mV[s_axis] = s/scale.mV[s_axis];
5585 v.mV[t_axis] = t/scale.mV[t_axis];
5586 }
5587
5588 mTextureScaleRatios.push_back(v);
5589 }
5590 }
5591}
5592
5593
5594// This implementation should be similar to LLTask::allowOperationOnTask
5595BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const
5596{
5597 // Extract ownership.
5598 BOOL object_is_group_owned = FALSE;
5599 LLUUID object_owner_id;
5600 mPermissions->getOwnership(object_owner_id, object_is_group_owned);
5601
5602 // Operations on invalid or public objects is not allowed.
5603 if (!mObject || (mObject->isDead()) || !mPermissions->isOwned())
5604 {
5605 return FALSE;
5606 }
5607
5608 // The transfer permissions can never be given through proxy.
5609 if (PERM_TRANSFER == op)
5610 {
5611 // The owner of an agent-owned object can transfer to themselves.
5612 if ( !object_is_group_owned
5613 && (gAgent.getID() == object_owner_id) )
5614 {
5615 return TRUE;
5616 }
5617 else
5618 {
5619 // Otherwise check aggregate permissions.
5620 return mObject->permTransfer();
5621 }
5622 }
5623
5624 if (PERM_MOVE == op
5625 || PERM_MODIFY == op)
5626 {
5627 // only owners can move or modify their attachments
5628 // no proxy allowed.
5629 if (mObject->isAttachment() && object_owner_id != gAgent.getID())
5630 {
5631 return FALSE;
5632 }
5633 }
5634
5635 // Calculate proxy_agent_id and group_id to use for permissions checks.
5636 // proxy_agent_id may be set to the object owner through group powers.
5637 // group_id can only be set to the object's group, if the agent is in that group.
5638 LLUUID group_id = LLUUID::null;
5639 LLUUID proxy_agent_id = gAgent.getID();
5640
5641 // Gods can always operate.
5642 if (gAgent.isGodlike())
5643 {
5644 return TRUE;
5645 }
5646
5647 // Check if the agent is in the same group as the object.
5648 LLUUID object_group_id = mPermissions->getGroup();
5649 if (object_group_id.notNull() &&
5650 gAgent.isInGroup(object_group_id))
5651 {
5652 // Assume the object's group during this operation.
5653 group_id = object_group_id;
5654 }
5655
5656 // Only allow proxy powers for PERM_COPY if the actual agent can
5657 // receive the item (ie has PERM_TRANSFER permissions).
5658 // NOTE: op == PERM_TRANSFER has already been handled, but if
5659 // that ever changes we need to BLOCK proxy powers for PERM_TRANSFER. DK 03/28/06
5660 if (PERM_COPY != op || mPermissions->allowTransferTo(gAgent.getID()))
5661 {
5662 // Check if the agent can assume ownership through group proxy or agent-granted proxy.
5663 if ( ( object_is_group_owned
5664 && gAgent.hasPowerInGroup(object_owner_id, group_proxy_power))
5665 // Only allow proxy for move, modify, and copy.
5666 || ( (PERM_MOVE == op || PERM_MODIFY == op || PERM_COPY == op)
5667 && (!object_is_group_owned
5668 && gAgent.isGrantedProxy(*mPermissions))))
5669 {
5670 // This agent is able to assume the ownership role for this operation.
5671 proxy_agent_id = object_owner_id;
5672 }
5673 }
5674
5675 // We now have max ownership information.
5676 if (PERM_OWNER == op)
5677 {
5678 // This this was just a check for ownership, we can now return the answer.
5679 return (proxy_agent_id == object_owner_id ? TRUE : FALSE);
5680 }
5681
5682 // check permissions to see if the agent can operate
5683 return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
5684}
5685
5686//-----------------------------------------------------------------------------
5687// renderOneSilhouette()
5688//-----------------------------------------------------------------------------
5689void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
5690{
5691 LLViewerObject* objectp = getObject();
5692 if (!objectp)
5693 {
5694 return;
5695 }
5696
5697 LLDrawable* drawable = objectp->mDrawable;
5698 if(!drawable)
5699 {
5700 return;
5701 }
5702
5703 if (!mSilhouetteExists)
5704 {
5705 return;
5706 }
5707
5708 BOOL is_hud_object = objectp->isHUDAttachment();
5709
5710 if (!drawable->isVisible() && !is_hud_object)
5711 {
5712 return;
5713 }
5714
5715 if (mSilhouetteVertices.size() == 0 || mSilhouetteNormals.size() != mSilhouetteVertices.size())
5716 {
5717 return;
5718 }
5719
5720 glMatrixMode(GL_MODELVIEW);
5721 glPushMatrix();
5722 if (!is_hud_object)
5723 {
5724 glLoadIdentity();
5725 glMultMatrixd(gGLModelView);
5726 }
5727
5728
5729 if (drawable->isActive())
5730 {
5731 glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix);
5732 }
5733
5734 LLVolume *volume = objectp->getVolume();
5735 if (volume)
5736 {
5737 F32 silhouette_thickness;
5738 if (is_hud_object && gAgent.getAvatarObject())
5739 {
5740 silhouette_thickness = LLSelectMgr::sHighlightThickness / gAgent.getAvatarObject()->mHUDCurZoom;
5741 }
5742 else
5743 {
5744 LLVector3 view_vector = gCamera->getOrigin() - objectp->getRenderPosition();
5745 silhouette_thickness = drawable->mDistanceWRTCamera * LLSelectMgr::sHighlightThickness * (gCamera->getView() / gCamera->getDefaultFOV());
5746 }
5747 F32 animationTime = (F32)LLFrameTimer::getElapsedSeconds();
5748
5749 F32 u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f);
5750 F32 v_coord = 1.f - fmod(animationTime * LLSelectMgr::sHighlightVAnim, 1.f);
5751 F32 u_divisor = 1.f / ((F32)(mSilhouetteVertices.size() - 1));
5752
5753 if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible())
5754 {
5755 glBlendFunc(GL_SRC_COLOR, GL_ONE);
5756 LLGLEnable fog(GL_FOG);
5757 glFogi(GL_FOG_MODE, GL_LINEAR);
5758 float d = (gCamera->getPointOfInterest()-gCamera->getOrigin()).magVec();
5759 LLColor4 fogCol = color * (F32)llclamp((gSelectMgr->getSelectionCenterGlobal()-gAgent.getCameraPositionGlobal()).magVec()/(gSelectMgr->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0);
5760 glFogf(GL_FOG_START, d);
5761 glFogf(GL_FOG_END, d*(1 + (gCamera->getView() / gCamera->getDefaultFOV())));
5762 glFogfv(GL_FOG_COLOR, fogCol.mV);
5763
5764 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
5765 glAlphaFunc(GL_GREATER, 0.01f);
5766 glBegin(GL_LINES);
5767 {
5768 S32 i = 0;
5769 for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++)
5770 {
5771// S32 first_i = i;
5772 for(; i < mSilhouetteSegments[seg_num]; i++)
5773 {
5774 u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
5775
5776 glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
5777 glTexCoord2f( u_coord, v_coord );
5778 glVertex3fv( mSilhouetteVertices[i].mV );
5779 }
5780
5781 /*u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
5782 glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
5783 glTexCoord2f( u_coord, v_coord );
5784 glVertex3fv( mSilhouetteVertices[first_i].mV );*/
5785 }
5786 }
5787 glEnd();
5788 u_coord = fmod(animationTime * LLSelectMgr::sHighlightUAnim, 1.f);
5789 }
5790
5791 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5792 //glAlphaFunc(GL_GREATER, LLSelectMgr::sHighlightAlphaTest);
5793 glBegin(GL_TRIANGLES);
5794 {
5795 S32 i = 0;
5796 for (S32 seg_num = 0; seg_num < (S32)mSilhouetteSegments.size(); seg_num++)
5797 {
5798 S32 first_i = i;
5799 LLVector3 v;
5800 LLVector2 t;
5801
5802 for(; i < mSilhouetteSegments[seg_num]; i++)
5803 {
5804
5805 if (i == first_i) {
5806 LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness;
5807 vert += mSilhouetteVertices[i];
5808
5809 glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
5810 glTexCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
5811 glVertex3fv( vert.mV );
5812
5813 u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
5814
5815 glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
5816 glTexCoord2f( u_coord, v_coord );
5817 glVertex3fv( mSilhouetteVertices[i].mV );
5818
5819 v = mSilhouetteVertices[i];
5820 t = LLVector2(u_coord, v_coord);
5821 }
5822 else {
5823 LLVector3 vert = (mSilhouetteNormals[i]) * silhouette_thickness;
5824 vert += mSilhouetteVertices[i];
5825
5826 glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.0f); //LLSelectMgr::sHighlightAlpha);
5827 glTexCoord2f( u_coord, v_coord + LLSelectMgr::sHighlightVScale );
5828 glVertex3fv( vert.mV );
5829 glVertex3fv( vert.mV );
5830
5831 glTexCoord2fv(t.mV);
5832 u_coord += u_divisor * LLSelectMgr::sHighlightUScale;
5833 glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
5834 glVertex3fv(v.mV);
5835 glTexCoord2f( u_coord, v_coord );
5836 glVertex3fv( mSilhouetteVertices[i].mV );
5837
5838 }
5839 }
5840 }
5841 }
5842 glEnd();
5843
5844 }
5845 glPopMatrix();
5846}
5847
5848//
5849// Utility Functions
5850//
5851
5852// Update everyone who cares about the selection list
5853void dialog_refresh_all()
5854{
5855 if (gNoRender)
5856 {
5857 return;
5858 }
5859
5860 //could refresh selected object info in toolbar here
5861
5862 gFloaterTools->dirty();
5863
5864 if( gPieObject->getVisible() )
5865 {
5866 gPieObject->arrange();
5867 }
5868
5869 LLFloaterProperties::dirtyAll();
5870 LLFloaterInspect::dirty();
5871}
5872
5873S32 get_family_count(LLViewerObject *parent)
5874{
5875 if (!parent)
5876 {
5877 llwarns << "Trying to get_family_count on null parent!" << llendl;
5878 }
5879 S32 count = 1; // for this object
5880 for (U32 i = 0; i < parent->mChildList.size(); i++)
5881 {
5882 LLViewerObject* child = parent->mChildList[i];
5883
5884 if (!child)
5885 {
5886 llwarns << "Family object has NULL child! Show Doug." << llendl;
5887 }
5888 else if (child->isDead())
5889 {
5890 llwarns << "Family object has dead child object. Show Doug." << llendl;
5891 }
5892 else
5893 {
5894 if (gSelectMgr->canSelectObject(child))
5895 {
5896 count += get_family_count( child );
5897 }
5898 }
5899 }
5900 return count;
5901}
5902
5903//-----------------------------------------------------------------------------
5904// updateSelectionCenter
5905//-----------------------------------------------------------------------------
5906void LLSelectMgr::updateSelectionCenter()
5907{
5908 const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection
5909 // center (tractor beam)
5910
5911 LLViewerObject* object = mSelectedObjects.getFirstObject();
5912 if (!object)
5913 {
5914 // nothing selected, probably grabbing
5915 // Ignore by setting to avatar origin.
5916 mSelectionCenterGlobal.clearVec();
5917 mShowSelection = FALSE;
5918 mSelectionBBox = LLBBox();
5919 mPauseRequest = NULL;
5920 if (gAgent.getAvatarObject())
5921 {
5922 gAgent.getAvatarObject()->mHUDTargetZoom = 1.f;
5923 gAgent.getAvatarObject()->mHUDCurZoom = 1.f;
5924 }
5925 }
5926 else
5927 {
5928 mSelectType = getSelectTypeForObject(object);
5929
5930 if (mSelectType == SELECT_TYPE_ATTACHMENT && gAgent.getAvatarObject())
5931 {
5932 mPauseRequest = gAgent.getAvatarObject()->requestPause();
5933 }
5934 else
5935 {
5936 mPauseRequest = NULL;
5937 }
5938
5939 if (mSelectType != SELECT_TYPE_HUD && gAgent.getAvatarObject())
5940 {
5941 // reset hud ZOOM
5942 gAgent.getAvatarObject()->mHUDTargetZoom = 1.f;
5943 gAgent.getAvatarObject()->mHUDCurZoom = 1.f;
5944 }
5945
5946 mShowSelection = FALSE;
5947 LLBBox bbox;
5948
5949 // have stuff selected
5950 LLVector3d select_center;
5951 // keep a list of jointed objects for showing the joint HUDEffects
5952 gHUDManager->clearJoints();
5953 LLDynamicArray < LLViewerObject *> jointed_objects;
5954
5955 for (object = mSelectedObjects.getFirstObject(); object; object = mSelectedObjects.getNextObject() )
5956 {
5957 LLViewerObject *myAvatar = gAgent.getAvatarObject();
5958 LLViewerObject *root = object->getRootEdit();
5959 if (mSelectType == SELECT_TYPE_WORLD && // not an attachment
5960 !root->isChild(myAvatar) && // not the object you're sitting on
5961 !object->isAvatar()) // not another avatar
5962 {
5963 mShowSelection = TRUE;
5964 }
5965
5966 bbox.addBBoxAgent( object->getBoundingBoxAgent() );
5967
5968 if (object->isJointChild())
5969 {
5970 jointed_objects.put(object);
5971 }
5972 } // end for
5973
5974 LLVector3 bbox_center_agent = bbox.getCenterAgent();
5975 mSelectionCenterGlobal = gAgent.getPosGlobalFromAgent(bbox_center_agent);
5976 mSelectionBBox = bbox;
5977
5978 if (jointed_objects.count())
5979 {
5980 gHUDManager->showJoints(&jointed_objects);
5981 }
5982 }
5983
5984 if ( !(gAgentID == LLUUID::null) )
5985 {
5986 LLTool *tool = gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) );
5987 if (mShowSelection)
5988 {
5989 LLVector3d select_center_global;
5990
5991 if( tool->isEditing() )
5992 {
5993 select_center_global = tool->getEditingPointGlobal();
5994 }
5995 else
5996 {
5997 select_center_global = mSelectionCenterGlobal;
5998 }
5999
6000 // Send selection center if moved beyond threshold (used to animate tractor beam)
6001 LLVector3d diff;
6002 diff = select_center_global - mLastSentSelectionCenterGlobal;
6003
6004 if ( diff.magVecSquared() > MOVE_SELECTION_THRESHOLD*MOVE_SELECTION_THRESHOLD )
6005 {
6006 // Transmit updated selection center
6007 mLastSentSelectionCenterGlobal = select_center_global;
6008 }
6009 }
6010 }
6011
6012 // give up edit menu if no objects selected
6013 if (gEditMenuHandler == this && getObjectCount() == 0)
6014 {
6015 gEditMenuHandler = NULL;
6016 }
6017}
6018
6019void LLSelectMgr::updatePointAt()
6020{
6021 if (mShowSelection)
6022 {
6023 if (getObjectCount())
6024 {
6025 LLVector3 select_offset;
6026 LLViewerObject *click_object = gObjectList.findObject(gLastHitObjectID);
6027 if (click_object && click_object->isSelected())
6028 {
6029 // clicked on another object in our selection group, use that as target
6030 select_offset.setVec(gLastHitObjectOffset);
6031 select_offset.rotVec(~click_object->getRenderRotation());
6032
6033 gAgent.setPointAt(POINTAT_TARGET_SELECT, click_object, select_offset);
6034 gAgent.setLookAt(LOOKAT_TARGET_SELECT, click_object, select_offset);
6035 }
6036 else
6037 {
6038 // didn't click on an object this time, revert to pointing at center of first object
6039 gAgent.setPointAt(POINTAT_TARGET_SELECT, getFirstObject());
6040 gAgent.setLookAt(LOOKAT_TARGET_SELECT, getFirstObject());
6041 }
6042 }
6043 else
6044 {
6045 gAgent.setPointAt(POINTAT_TARGET_CLEAR);
6046 gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
6047 }
6048 }
6049 else
6050 {
6051 gAgent.setPointAt(POINTAT_TARGET_CLEAR);
6052 gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
6053 }
6054}
6055
6056//-----------------------------------------------------------------------------
6057// getBBoxOfSelection()
6058//-----------------------------------------------------------------------------
6059LLBBox LLSelectMgr::getBBoxOfSelection() const
6060{
6061 return mSelectionBBox;
6062}
6063
6064
6065//-----------------------------------------------------------------------------
6066// canUndo()
6067//-----------------------------------------------------------------------------
6068BOOL LLSelectMgr::canUndo()
6069{
6070 return getFirstEditableObject() != NULL;
6071}
6072
6073//-----------------------------------------------------------------------------
6074// undo()
6075//-----------------------------------------------------------------------------
6076void LLSelectMgr::undo()
6077{
6078 BOOL select_linked_set = gSavedSettings.getBOOL("SelectLinkedSet");
6079 LLUUID group_id(gAgent.getGroupID());
6080 sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
6081}
6082
6083//-----------------------------------------------------------------------------
6084// canRedo()
6085//-----------------------------------------------------------------------------
6086BOOL LLSelectMgr::canRedo()
6087{
6088 return getFirstEditableObject() != NULL;
6089}
6090
6091//-----------------------------------------------------------------------------
6092// redo()
6093//-----------------------------------------------------------------------------
6094void LLSelectMgr::redo()
6095{
6096 BOOL select_linked_set = gSavedSettings.getBOOL("SelectLinkedSet");
6097 LLUUID group_id(gAgent.getGroupID());
6098 sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST);
6099}
6100
6101//-----------------------------------------------------------------------------
6102// canDoDelete()
6103//-----------------------------------------------------------------------------
6104BOOL LLSelectMgr::canDoDelete()
6105{
6106 return getFirstDeleteableObject() != NULL;
6107}
6108
6109//-----------------------------------------------------------------------------
6110// doDelete()
6111//-----------------------------------------------------------------------------
6112void LLSelectMgr::doDelete()
6113{
6114 selectDelete();
6115}
6116
6117//-----------------------------------------------------------------------------
6118// canDeselect()
6119//-----------------------------------------------------------------------------
6120BOOL LLSelectMgr::canDeselect()
6121{
6122 return !isEmpty();
6123}
6124
6125//-----------------------------------------------------------------------------
6126// deselect()
6127//-----------------------------------------------------------------------------
6128void LLSelectMgr::deselect()
6129{
6130 deselectAll();
6131}
6132//-----------------------------------------------------------------------------
6133// canDuplicate()
6134//-----------------------------------------------------------------------------
6135BOOL LLSelectMgr::canDuplicate()
6136{
6137 return getFirstCopyableObject() != NULL;
6138}
6139//-----------------------------------------------------------------------------
6140// duplicate()
6141//-----------------------------------------------------------------------------
6142void LLSelectMgr::duplicate()
6143{
6144 LLVector3 offset(0.5f, 0.5f, 0.f);
6145 selectDuplicate(offset, TRUE);
6146}
6147//-----------------------------------------------------------------------------
6148// undoRedo()
6149//-----------------------------------------------------------------------------
6150U32 LLSelectMgr::undoRedo(std::deque<LLSelectAction*> &queue_src, std::deque<LLSelectAction*> &queue_dst, const LLUUID &object_id)
6151{
6152 if (queue_src.size() == 0)
6153 {
6154 return 0;
6155 }
6156
6157 U32 update_type = 0;
6158 std::deque<LLSelectAction*> temp_queue;
6159 LLSelectAction* src_actionp = queue_src.back();
6160
6161 while (src_actionp->mObjectID != object_id)
6162 {
6163 temp_queue.push_back(src_actionp);
6164 queue_src.pop_back();
6165 if (!queue_src.size())
6166 {
6167 // put everything back
6168 LLSelectAction* actionp;
6169 while (temp_queue.size())
6170 {
6171 actionp = temp_queue.back();
6172 temp_queue.pop_back();
6173 queue_src.push_back(actionp);
6174 }
6175 return 0;
6176 }
6177 src_actionp = queue_src.back();
6178 }
6179
6180 if(src_actionp)
6181 {
6182 LLSelectAction* dst_actionp = new LLSelectAction();
6183 dst_actionp->mActionType = src_actionp->mActionType;
6184 dst_actionp->mObjectID = src_actionp->mObjectID;
6185 dst_actionp->mIndividualSelection = src_actionp->mIndividualSelection;
6186
6187 LLViewerObject* object = gObjectList.findObject(src_actionp->mObjectID);
6188 if (object && object->mDrawable.notNull())
6189 {
6190 LLVector3 old_position_local = object->getPosition();
6191
6192 switch(src_actionp->mActionType)
6193 {
6194 case SELECT_ACTION_TYPE_MOVE:
6195 dst_actionp->mPosition = object->mDrawable->getPosition();
6196 object->setPosition(src_actionp->mPosition, TRUE);
6197 if (object->isRootEdit() && src_actionp->mIndividualSelection)
6198 {
6199 // counter-translate children
6200 LLVector3 parent_offset = (src_actionp->mPosition - old_position_local) * ~object->getRotation();
6201
6202 // counter-translate child objects if we are moving the root as an individual
6203 for (U32 child_num = 0; child_num < object->mChildList.size(); child_num++)
6204 {
6205 LLViewerObject* childp = object->mChildList[child_num];
6206 childp->setPosition(childp->getPosition() - parent_offset);
6207 }
6208 }
6209 update_type |= UPD_POSITION;
6210 break;
6211 case SELECT_ACTION_TYPE_ROTATE:
6212 dst_actionp->mPosition = object->mDrawable->getPosition();
6213 dst_actionp->mRotation = object->mDrawable->getRotation();
6214 object->setRotation(src_actionp->mRotation, TRUE);
6215 object->setPosition(src_actionp->mPosition, TRUE);
6216 if (object->isRootEdit() && src_actionp->mIndividualSelection)
6217 {
6218 // counter-translate and rotate children
6219 LLVector3 parent_offset = (src_actionp->mPosition - old_position_local) * ~object->getRotation();
6220
6221 for (U32 child_num = 0; child_num < object->mChildList.size(); child_num++)
6222 {
6223 LLViewerObject* childp = object->mChildList[child_num];
6224 LLQuaternion delta_rot_inv = dst_actionp->mRotation * ~src_actionp->mRotation;
6225 childp->setPosition((childp->getPosition() * delta_rot_inv) - parent_offset);
6226 childp->setRotation(childp->getRotation() * delta_rot_inv );
6227 }
6228 }
6229 update_type |= UPD_ROTATION | UPD_POSITION;
6230 break;
6231 case SELECT_ACTION_TYPE_SCALE:
6232 dst_actionp->mPosition = object->mDrawable->getPosition();
6233 dst_actionp->mScale = object->getScale();
6234 object->setScale(src_actionp->mScale, TRUE);
6235 object->setPosition(src_actionp->mPosition, TRUE);
6236 update_type |= UPD_SCALE | UPD_POSITION;
6237 break;
6238 default:
6239 // do nothing
6240 break;
6241 }
6242 }
6243 queue_src.pop_back();
6244 delete src_actionp;
6245 queue_dst.push_back(dst_actionp);
6246 while (queue_dst.size() > (U32)MAX_ACTION_QUEUE_SIZE)
6247 {
6248 LLSelectAction* action = queue_dst.front();
6249 queue_dst.pop_front();
6250 delete action;
6251 }
6252
6253 }
6254
6255 // put everything back
6256 LLSelectAction* actionp;
6257 while (temp_queue.size())
6258 {
6259 actionp = temp_queue.back();
6260 temp_queue.pop_back();
6261 queue_src.push_back(actionp);
6262 }
6263
6264 return update_type;
6265}
6266
6267ESelectType LLSelectMgr::getSelectTypeForObject(LLViewerObject* object)
6268{
6269 if (!object)
6270 {
6271 return SELECT_TYPE_WORLD;
6272 }
6273 if (object->isHUDAttachment())
6274 {
6275 return SELECT_TYPE_HUD;
6276 }
6277 else if (object->isAttachment())
6278 {
6279 return SELECT_TYPE_ATTACHMENT;
6280 }
6281 else
6282 {
6283 return SELECT_TYPE_WORLD;
6284 }
6285}
6286
6287void LLSelectMgr::validateSelection()
6288{
6289 LLViewerObject* objectp;
6290 for (objectp = getFirstObject(); objectp; objectp = getNextObject())
6291 {
6292 if (!canSelectObject(objectp))
6293 {
6294 deselectObjectOnly(objectp);
6295 }
6296 }
6297}
6298
6299BOOL LLSelectMgr::canSelectObject(LLViewerObject* object)
6300{
6301 if (mForceSelection)
6302 {
6303 return TRUE;
6304 }
6305
6306 if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) ||
6307 (gSavedSettings.getBOOL("SelectMovableOnly") && !object->permMove()))
6308 {
6309 // only select my own objects
6310 return FALSE;
6311 }
6312
6313 // Can't select dead objects
6314 if (object->isDead()) return FALSE;
6315
6316 // Can't select orphans
6317 if (object->isOrphaned()) return FALSE;
6318
6319 // Can't select avatars
6320 if (object->isAvatar()) return FALSE;
6321
6322 // Can't select land
6323 if (object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) return FALSE;
6324
6325 ESelectType selection_type = getSelectTypeForObject(object);
6326 if (getObjectCount() > 0 && mSelectType != selection_type) return FALSE;
6327
6328 return TRUE;
6329}
6330
6331LLSelectNodeList::LLSelectNodeList() : std::list<LLSelectNode*>()
6332{
6333 mCurrentTE = -1;
6334 mCurrentNode = end();
6335}
6336
6337LLSelectNodeList::~LLSelectNodeList()
6338{
6339 std::for_each(begin(), end(), DeletePointer());
6340}
6341
6342void LLSelectNodeList::updateEffects()
6343{
6344}
6345
6346S32 LLSelectNodeList::getNumNodes()
6347{
6348 return size();
6349}
6350
6351void LLSelectNodeList::addNode(LLSelectNode *nodep)
6352{
6353 push_front(nodep);
6354 mSelectNodeMap[nodep->getObject()] = nodep;
6355}
6356
6357void LLSelectNodeList::addNodeAtEnd(LLSelectNode *nodep)
6358{
6359 push_back(nodep);
6360 mSelectNodeMap[nodep->getObject()] = nodep;
6361}
6362
6363void LLSelectNodeList::removeNode(LLSelectNode *nodep)
6364{
6365 std::list<LLSelectNode*>::iterator iter;
6366 for (iter = begin(); iter != end(); ++iter)
6367 {
6368 if ((*iter) == nodep)
6369 {
6370 mSelectNodeMap.erase(nodep->getObject());
6371 erase(iter++);
6372 }
6373 }
6374}
6375
6376void LLSelectNodeList::deleteAllNodes()
6377{
6378 std::for_each(begin(), end(), DeletePointer());
6379 clear();
6380 mSelectNodeMap.clear();
6381}
6382
6383LLSelectNode* LLSelectNodeList::findNode(LLViewerObject* objectp)
6384{
6385 std::map<LLViewerObject*, LLSelectNode*>::iterator found_it = mSelectNodeMap.find(objectp);
6386 if (found_it != mSelectNodeMap.end())
6387 {
6388 return found_it->second;
6389 }
6390 return NULL;
6391}
6392
6393//-----------------------------------------------------------------------------
6394// getFirstNode()
6395//-----------------------------------------------------------------------------
6396LLSelectNode *LLSelectNodeList::getFirstNode()
6397{
6398 mCurrentNode = begin();//getFirstData();
6399
6400 while (mCurrentNode != end() && !(*mCurrentNode)->getObject())
6401 {
6402 // The object on this was killed at some point, delete it.
6403 erase(mCurrentNode++);
6404 }
6405
6406 if (mCurrentNode != end())
6407 {
6408 return *mCurrentNode;
6409 }
6410
6411 return NULL;
6412}
6413
6414//-----------------------------------------------------------------------------
6415// getCurrentNode()
6416//-----------------------------------------------------------------------------
6417LLSelectNode *LLSelectNodeList::getCurrentNode()
6418{
6419 while (mCurrentNode != end() && !(*mCurrentNode)->getObject())
6420 {
6421 // The object on this was killed at some point, delete it.
6422 erase(mCurrentNode++);
6423 }
6424
6425 if (mCurrentNode != end())
6426 {
6427 return *mCurrentNode;
6428 }
6429 return NULL;
6430}
6431
6432//-----------------------------------------------------------------------------
6433// getNextNode()
6434//-----------------------------------------------------------------------------
6435LLSelectNode *LLSelectNodeList::getNextNode()
6436{
6437 ++mCurrentNode;
6438
6439 while (mCurrentNode != end() && !(*mCurrentNode)->getObject())
6440 {
6441 // The object on this was killed at some point, delete it.
6442 erase(mCurrentNode++);
6443 }
6444
6445 if (mCurrentNode != end())
6446 {
6447 return *mCurrentNode;
6448 }
6449 return NULL;
6450}
6451
6452
6453
6454//-----------------------------------------------------------------------------
6455// getFirstObject()
6456//-----------------------------------------------------------------------------
6457LLViewerObject* LLSelectNodeList::getFirstObject()
6458{
6459 mCurrentNode = begin();
6460
6461 while (mCurrentNode != end() && !(*mCurrentNode)->getObject())
6462 {
6463 // The object on this was killed at some point, delete it.
6464 erase(mCurrentNode++);
6465 }
6466
6467 if (mCurrentNode != end())
6468 {
6469 return (*mCurrentNode)->getObject();
6470 }
6471
6472 return NULL;
6473}
6474
6475
6476//-----------------------------------------------------------------------------
6477// getNextObject()
6478//-----------------------------------------------------------------------------
6479LLViewerObject* LLSelectNodeList::getNextObject()
6480{
6481 ++mCurrentNode;// = getNextData();
6482
6483 while (mCurrentNode != end() && !(*mCurrentNode)->getObject())
6484 {
6485 // The object on this was killed at some point, delete it.
6486 erase(mCurrentNode++);
6487 }
6488
6489 if (mCurrentNode != end())
6490 {
6491 return (*mCurrentNode)->getObject();
6492 }
6493
6494 return NULL;
6495}
6496
6497
6498
6499//-----------------------------------------------------------------------------
6500// getPrimaryTE()
6501//-----------------------------------------------------------------------------
6502void LLSelectNodeList::getPrimaryTE(LLViewerObject* *object, S32 *te)
6503{
6504 // initialize object and te
6505 *te = 0;
6506 *object = NULL;
6507
6508 BOOL searching_roots = TRUE;
6509
6510 // try for root node first, then first child node
6511 LLSelectNode *primary_node = getFirstNode(); //getFirstRootNode();
6512 if (!primary_node)
6513 {
6514 primary_node = getFirstNode();
6515 searching_roots = FALSE;
6516 }
6517
6518 while (primary_node)
6519 {
6520 S32 last_selected_te = primary_node->getLastSelectedTE();
6521 if (last_selected_te >= 0)
6522 {
6523 *object = primary_node->getObject();
6524 *te = last_selected_te;
6525 return;
6526 }
6527 for(S32 cur_te = 0; cur_te < primary_node->getObject()->getNumTEs(); cur_te++)
6528 {
6529 // if face selected
6530 if (primary_node->isTESelected(cur_te))
6531 {
6532 // return this object and face
6533 *object = primary_node->getObject();
6534 *te = cur_te;
6535 return;
6536 }
6537 }
6538 if (searching_roots)
6539 {
6540 primary_node = getNextRootNode();
6541 if (!primary_node)
6542 {
6543 primary_node = getFirstNode();
6544 searching_roots = FALSE;
6545 }
6546 }
6547 else
6548 {
6549 primary_node = getNextNode();
6550 }
6551 }
6552}
6553
6554//-----------------------------------------------------------------------------
6555// getFirstTE()
6556//-----------------------------------------------------------------------------
6557void LLSelectNodeList::getFirstTE(LLViewerObject* *object, S32 *te)
6558{
6559 // start with first face
6560 mCurrentTE = 0;
6561
6562 LLSelectNode *cur_node = getFirstNode();
6563
6564 // repeat over all selection nodes
6565 while (cur_node)
6566 {
6567 // skip objects with no faces
6568 if (cur_node->getObject()->getNumTEs() == 0)
6569 {
6570 mCurrentTE = 0;
6571 cur_node = getNextNode();
6572 continue;
6573 }
6574
6575 // repeat over all faces for this object
6576 while (mCurrentTE < cur_node->getObject()->getNumTEs())
6577 {
6578 // if face selected
6579 if (cur_node->isTESelected(mCurrentTE))
6580 {
6581 // return this object and face
6582 *object = cur_node->getObject();
6583 *te = mCurrentTE;
6584 return;
6585 }
6586
6587 mCurrentTE++;
6588 }
6589
6590 // Couldn't find a selected face.
6591 // This can happen if an object's volume parameters are changed in such a way
6592 // that texture entries are eliminated.
6593 //
6594 // TODO: Consider selecting all faces in this case? Subscribe the selection
6595 // list to the volume changing code?
6596
6597 mCurrentTE = 0;
6598 cur_node = getNextNode();
6599 }
6600
6601 // The list doesn't contain any nodes. Return NULL.
6602 *object = NULL;
6603 *te = -1;
6604 return;
6605}
6606
6607
6608//-----------------------------------------------------------------------------
6609// getNextFace()
6610//-----------------------------------------------------------------------------
6611void LLSelectNodeList::getNextTE(LLViewerObject* *object, S32 *te)
6612{
6613 // try next face
6614 mCurrentTE++;
6615
6616 LLSelectNode *cur_node = getCurrentNode();
6617 // repeat over remaining selection nodes
6618 while ( cur_node )
6619 {
6620 // skip objects with no faces
6621 if (cur_node->getObject()->getNumTEs() == 0)
6622 {
6623 mCurrentTE = 0;
6624 cur_node = getNextNode();
6625 continue;
6626 }
6627
6628 // repeat over all faces for this object
6629 // CRO: getNumTEs() no longer equals mFaces.count(), so use mFaces.count() instead
6630 while ( mCurrentTE < cur_node->getObject()->getNumTEs() )
6631 {
6632 // if face selected
6633 if (cur_node->isTESelected(mCurrentTE))
6634 {
6635 // return this object and face
6636 *object = cur_node->getObject();
6637 *te = mCurrentTE;
6638 return;
6639 }
6640
6641 mCurrentTE++;
6642 }
6643
6644 mCurrentTE = 0;
6645 cur_node = getNextNode();
6646 }
6647
6648 // The list doesn't contain any nodes. Return NULL.
6649 *object = NULL;
6650 *te = -1;
6651 return;
6652}
6653
6654void LLSelectNodeList::getCurrentTE(LLViewerObject* *object, S32 *te)
6655{
6656 if (mCurrentNode != end())
6657 {
6658 *object = (*mCurrentNode)->getObject();
6659 *te = mCurrentTE;
6660 }
6661 else
6662 {
6663 *object = NULL;
6664 *te = -1;
6665 }
6666}
6667//-----------------------------------------------------------------------------
6668// getFirstRootNode()
6669//-----------------------------------------------------------------------------
6670LLSelectNode *LLSelectNodeList::getFirstRootNode()
6671{
6672 LLSelectNode *cur_node = getFirstNode();
6673
6674 // scan through child objects and roots set to ignore
6675 while (cur_node &&
6676 (!(cur_node->getObject()->isRootEdit() || cur_node->getObject()->isJointChild()) ||
6677 cur_node->mIndividualSelection))
6678 {
6679 cur_node = getNextNode();
6680 }
6681
6682 return cur_node;
6683}
6684
6685
6686//-----------------------------------------------------------------------------
6687// getNextRootNode()
6688//-----------------------------------------------------------------------------
6689LLSelectNode *LLSelectNodeList::getNextRootNode()
6690{
6691 LLSelectNode *cur_node = getNextNode();
6692
6693 while (cur_node &&
6694 (!(cur_node->getObject()->isRootEdit() || cur_node->getObject()->isJointChild()) ||
6695 cur_node->mIndividualSelection))
6696 {
6697 cur_node = getNextNode();
6698 }
6699
6700 return cur_node;
6701}
6702
6703
6704//-----------------------------------------------------------------------------
6705// getFirstRootObject()
6706//-----------------------------------------------------------------------------
6707LLViewerObject *LLSelectNodeList::getFirstRootObject()
6708{
6709 LLSelectNode *node = getFirstRootNode();
6710
6711 if (node)
6712 {
6713 return node->getObject();
6714 }
6715 else
6716 {
6717 return NULL;
6718 }
6719}
6720
6721
6722//-----------------------------------------------------------------------------
6723// getNextRootObject()
6724//-----------------------------------------------------------------------------
6725LLViewerObject *LLSelectNodeList::getNextRootObject()
6726{
6727 LLSelectNode *node = getNextRootNode();
6728
6729 if (node)
6730 {
6731 return node->getObject();
6732 }
6733 else
6734 {
6735 return NULL;
6736 }
6737}
6738
6739//-----------------------------------------------------------------------------
6740// isEmpty()
6741//-----------------------------------------------------------------------------
6742BOOL LLSelectNodeList::isEmpty()
6743{
6744 return (size() == 0);
6745}
6746
6747//-----------------------------------------------------------------------------
6748// getOwnershipCost()
6749//-----------------------------------------------------------------------------
6750BOOL LLSelectNodeList::getOwnershipCost(S32 &cost)
6751{
6752 S32 count = 0;
6753 for( LLSelectNode* nodep = getFirstNode(); nodep; nodep = getNextNode() )
6754 {
6755 count++;
6756 }
6757
6758 cost = count * OWNERSHIP_COST_PER_OBJECT;
6759
6760 return (count > 0);
6761}