// the selection bbox isn't axis aligned, so we must construct one
// should this be cached in the selection manager?  yes.
LLBBox get_selection_axis_aligned_bbox()
{
	LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
	LLVector3 position = selection_bbox.getPositionAgent();
	
	LLBBox axis_aligned_bbox = LLBBox(position, LLQuaternion(), LLVector3(), LLVector3());
	axis_aligned_bbox.addPointLocal(LLVector3());

	// cycle over the nodes in selection
	for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin();
		 selection_iter != LLSelectMgr::getInstance()->getSelection()->end();
		 ++selection_iter)
	{
		LLSelectNode *select_node = *selection_iter;
		if (select_node)
		{
			LLViewerObject* object = select_node->getObject();
			if (object)
			{
				axis_aligned_bbox.addBBoxAgent(object->getBoundingBoxAgent());
			}
		}
	}

	
	return axis_aligned_bbox;
}
Example #2
0
// True if you selected an object.
BOOL LLToolPie::pickLeftMouseDownCallback()
{
	S32 x = mPick.mMousePt.mX;
	S32 y = mPick.mMousePt.mY;
	MASK mask = mPick.mKeyMask;
	if (mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL)
	{
		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getCollisionParcel();
		if (parcel)
		{
			LLViewerParcelMgr::getInstance()->selectCollisionParcel();
			if (parcel->getParcelFlag(PF_USE_PASS_LIST) 
				&& !LLViewerParcelMgr::getInstance()->isCollisionBanned())
			{
				// if selling passes, just buy one
				void* deselect_when_done = (void*)TRUE;
				LLPanelLandGeneral::onClickBuyPass(deselect_when_done);
			}
			else
			{
				// not selling passes, get info
				LLFloaterReg::showInstance("about_land");
			}
		}

		gFocusMgr.setKeyboardFocus(NULL);
		return LLTool::handleMouseDown(x, y, mask);
	}

	// didn't click in any UI object, so must have clicked in the world
	LLViewerObject *object = mPick.getObject();
	LLViewerObject *parent = NULL;

	if (mPick.mPickType != LLPickInfo::PICK_LAND)
	{
		LLViewerParcelMgr::getInstance()->deselectLand();
	}
	
	if (object)
	{
		parent = object->getRootEdit();
	}

	if (handleMediaClick(mPick))
	{
		return TRUE;
	}

	// If it's a left-click, and we have a special action, do it.
	if (useClickAction(mask, object, parent))
	{
		mClickAction = 0;
		if (object && object->getClickAction()) 
		{
			mClickAction = object->getClickAction();
		}
		else if (parent && parent->getClickAction()) 
		{
			mClickAction = parent->getClickAction();
		}

		switch(mClickAction)
		{
		case CLICK_ACTION_TOUCH:
			// touch behavior down below...
			break;
		case CLICK_ACTION_SIT:
			{
				if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // agent not already sitting
				{
					handle_object_sit_or_stand();
					// put focus in world when sitting on an object
					gFocusMgr.setKeyboardFocus(NULL);
					return TRUE;
				} // else nothing (fall through to touch)
			}
		case CLICK_ACTION_PAY:
			if ((object && object->flagTakesMoney())
				|| (parent && parent->flagTakesMoney()))
			{
				// pay event goes to object actually clicked on
				mClickActionObject = object;
				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
				if (LLSelectMgr::getInstance()->selectGetAllValid())
				{
					// call this right away, since we have all the info we need to continue the action
					selectionPropertiesReceived();
				}
				return TRUE;
			}
			break;
		case CLICK_ACTION_BUY:
			mClickActionObject = parent;
			mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
			if (LLSelectMgr::getInstance()->selectGetAllValid())
			{
				// call this right away, since we have all the info we need to continue the action
				selectionPropertiesReceived();
			}
			return TRUE;
		case CLICK_ACTION_OPEN:
			if (parent && parent->allowOpen())
			{
				mClickActionObject = parent;
				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
				if (LLSelectMgr::getInstance()->selectGetAllValid())
				{
					// call this right away, since we have all the info we need to continue the action
					selectionPropertiesReceived();
				}
			}
			return TRUE;	
		case CLICK_ACTION_PLAY:
			handle_click_action_play();
			return TRUE;
		case CLICK_ACTION_OPEN_MEDIA:
			// mClickActionObject = object;
			handle_click_action_open_media(object);
			return TRUE;
		case CLICK_ACTION_ZOOM:
			{	
				const F32 PADDING_FACTOR = 2.f;
				LLViewerObject* object = gObjectList.findObject(mPick.mObjectID);
				
				if (object)
				{
					gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
					
					LLBBox bbox = object->getBoundingBoxAgent() ;
					F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
					F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
				
					LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent();
					obj_to_cam.normVec();
					
					LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
					gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), 
													  object_center_global, 
													  mPick.mObjectID );
				}
			}
			return TRUE;			
		default:
			// nothing
			break;
		}
	}

	// put focus back "in world"
	gFocusMgr.setKeyboardFocus(NULL);

	BOOL touchable = (object && object->flagHandleTouch()) 
					 || (parent && parent->flagHandleTouch());

	// Switch to grab tool if physical or triggerable
	if (object && 
		!object->isAvatar() && 
		((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) 
		)
	{
		gGrabTransientTool = this;
		LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
		return LLToolGrab::getInstance()->handleObjectHit( mPick );
	}
	
	LLHUDIcon* last_hit_hud_icon = mPick.mHUDIcon;
	if (!object && last_hit_hud_icon && last_hit_hud_icon->getSourceObject())
	{
		LLFloaterScriptDebug::show(last_hit_hud_icon->getSourceObject()->getID());
	}

	// If left-click never selects or spawns a menu
	// Eat the event.
	if (!gSavedSettings.getBOOL("LeftClickShowMenu"))
	{
		// mouse already released
		if (!mGrabMouseButtonDown)
		{
			return TRUE;
		}

		while( object && object->isAttachment() && !object->flagHandleTouch())
		{
			// don't pick avatar through hud attachment
			if (object->isHUDAttachment())
			{
				break;
			}
			object = (LLViewerObject*)object->getParent();
		}
		if (object && object == gAgentAvatarp)
		{
			// we left clicked on avatar, switch to focus mode
			LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
			gViewerWindow->hideCursor();
			LLToolCamera::getInstance()->setMouseCapture(TRUE);
			LLToolCamera::getInstance()->pickCallback(mPick);
			gAgentCamera.setFocusOnAvatar(TRUE, TRUE);

			return TRUE;
		}
	//////////
	//	// Could be first left-click on nothing
	//	LLFirstUse::useLeftClickNoHit();
	/////////
		
		// Eat the event
		return LLTool::handleMouseDown(x, y, mask);
	}

	if (gAgent.leftButtonGrabbed())
	{
		// if the left button is grabbed, don't put up the pie menu
		return LLTool::handleMouseDown(x, y, mask);
	}

	// Can't ignore children here.
	LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);

	// Spawn pie menu
	LLTool::handleRightMouseDown(x, y, mask);
	return TRUE;
}
void QToolAlign::align()
{
	// no linkset parts, please
	LLSelectMgr::getInstance()->promoteSelectionToRoot();
	
	std::vector<LLPointer<LLViewerObject> > objects;
	std::map<LLPointer<LLViewerObject>, LLBBox > original_bboxes;
	
    // cycle over the nodes in selection and collect them into an array
	for (LLObjectSelection::root_iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
		 selection_iter != LLSelectMgr::getInstance()->getSelection()->root_end();
		 ++selection_iter)
	{
		LLSelectNode *select_node = *selection_iter;
		if (select_node)
		{
			LLViewerObject* object = select_node->getObject();
			if (object)
			{
				LLVector3 position = object->getPositionAgent();
	
				LLBBox bbox = LLBBox(position, LLQuaternion(), LLVector3(), LLVector3());
				bbox.addPointLocal(LLVector3());

				// add the parent's bbox
				bbox.addBBoxAgent(object->getBoundingBoxAgent());
				LLViewerObject::const_child_list_t& children = object->getChildren();

				for (LLViewerObject::const_child_list_t::const_iterator i = children.begin();
					 i != children.end(); i++)
				{
					// add the child's bbox
					LLViewerObject* child = *i;
					bbox.addBBoxAgent(child->getBoundingBoxAgent());
				}
				
				objects.push_back(object);
				original_bboxes[object] = bbox;
			}
		}
	}

	S32 axis = mHighlightedAxis;
	F32 direction = mHighlightedDirection;

	// sort them into positional order for proper packing
	BBoxCompare compare(axis, direction, original_bboxes);
	sort(objects.begin(), objects.end(), compare);

	// storage for their new position after alignment - start with original position first
	std::map<LLPointer<LLViewerObject>, LLBBox > new_bboxes = original_bboxes;

	// find new positions
	for (U32 i = 0; i < objects.size(); i++)
	{
		LLBBox target_bbox = mBBox;
		LLVector3 target_corner = target_bbox.getCenterAgent() - 
			direction * target_bbox.getExtentLocal() / 2.0;
	
		LLViewerObject* object = objects[i];

		LLBBox this_bbox = original_bboxes[object];
		LLVector3 this_corner = this_bbox.getCenterAgent() -
			direction * this_bbox.getExtentLocal() / 2.0;

		// for packing, we cycle over several possible positions, taking the smallest that does not overlap
		F32 smallest = direction * 9999999;  // 999999 guarenteed not to be the smallest
		for (U32 j = 0; j <= i; j++)
		{
			// how far must it move?
			LLVector3 delta = target_corner - this_corner;

			// new position moves only on one axis, please
			LLVector3 delta_one_axis = LLVector3(0,0,0);
			delta_one_axis.mV[axis] = delta.mV[axis];
			
			LLVector3 new_position = this_bbox.getCenterAgent() + delta_one_axis;

			// construct the new bbox
			LLBBox new_bbox = LLBBox(new_position, LLQuaternion(), LLVector3(), LLVector3());
			new_bbox.addPointLocal(this_bbox.getExtentLocal() / 2.0);
			new_bbox.addPointLocal(-1.0 * this_bbox.getExtentLocal() / 2.0);

			// check to see if it overlaps the previously placed objects
			BOOL overlap = FALSE;

			llwarns << "i=" << i << " j=" << j << llendl;
			
			if (!mForce) // well, don't check if in force mode
			{
				for (U32 k = 0; k < i; k++)
				{
					LLViewerObject* other_object = objects[k];
					LLBBox other_bbox = new_bboxes[other_object];

					BOOL overlaps_this = bbox_overlap(other_bbox, new_bbox);

					if (overlaps_this)
					{
						llwarns << "overlap" << new_bbox.getCenterAgent() << other_bbox.getCenterAgent() << llendl;
						llwarns << "extent" << new_bbox.getExtentLocal() << other_bbox.getExtentLocal() << llendl;
					}

					overlap = (overlap || overlaps_this);
				}
			}

			if (!overlap)
			{
				F32 this_value = (new_bbox.getCenterAgent() -
								  direction * new_bbox.getExtentLocal() / 2.0).mV[axis];

				if (direction * this_value < direction * smallest)
				{
					smallest = this_value;
					// store it
					new_bboxes[object] = new_bbox;
				}
			}

			// update target for next time through the loop
			if (j < objects.size())
			{
				LLBBox next_bbox = new_bboxes[objects[j]];
				target_corner = next_bbox.getCenterAgent() +
					direction * next_bbox.getExtentLocal() / 2.0;
			}
		}
	}

	
	// now move them in (Unsigned not Signed in 2.0)
	for (U32 i = 0; i < objects.size(); i++)
{
		LLViewerObject* object = objects[i];

		LLBBox original_bbox = original_bboxes[object];
		LLBBox new_bbox = new_bboxes[object];

		LLVector3 delta = new_bbox.getCenterAgent() - original_bbox.getCenterAgent();
		
		LLVector3 original_position = object->getPositionAgent();
		LLVector3 new_position = original_position + delta;

		object->setPosition(new_position);
	}
	
	
	LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
}