summaryrefslogtreecommitdiff
path: root/indra/newview/llviewermediafocus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewermediafocus.cpp')
-rw-r--r--indra/newview/llviewermediafocus.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
new file mode 100644
index 0000000000..60eabd730f
--- /dev/null
+++ b/indra/newview/llviewermediafocus.cpp
@@ -0,0 +1,355 @@
+/**
+ * @file llviewermediafocus.cpp
+ * @brief Governs focus on Media prims
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ *
+ * Copyright (c) 2003-2007, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewermediafocus.h"
+
+//LLViewerMediaFocus
+#include "llviewerobjectlist.h"
+#include "llpanelmediahud.h"
+#include "llpluginclassmedia.h"
+#include "llagent.h"
+#include "lltoolpie.h"
+#include "llviewercamera.h"
+#include "llviewermedia.h"
+#include "llhudview.h"
+#include "lluictrlfactory.h"
+#include "lldrawable.h"
+#include "llparcel.h"
+#include "llviewerparcelmgr.h"
+#include "llweb.h"
+//
+// LLViewerMediaFocus
+//
+
+LLViewerMediaFocus::LLViewerMediaFocus()
+: mMouseOverFlag(false)
+{
+}
+
+LLViewerMediaFocus::~LLViewerMediaFocus()
+{
+ // The destructor for LLSingletons happens at atexit() time, which is too late to do much.
+ // Clean up in cleanupClass() instead.
+}
+
+void LLViewerMediaFocus::cleanupClass()
+{
+ LLViewerMediaFocus *self = LLViewerMediaFocus::getInstance();
+
+ if(self)
+ {
+ // mMediaHUD will have been deleted by this point -- don't try to delete it.
+
+ /* Richard says:
+ all widgets are supposed to be destroyed at the same time
+ you shouldn't hold on to pointer to them outside of ui code
+ you can use the LLHandle approach
+ if you want to be type safe, you'll need to add a LLRootHandle to whatever derived class you are pointing to
+ look at llview::gethandle
+ its our version of a weak pointer
+ */
+ if(self->mMediaHUD.get())
+ {
+ self->mMediaHUD.get()->setMediaImpl(NULL);
+ }
+ self->mMediaImpl = NULL;
+ }
+
+}
+
+
+void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl )
+{
+ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (b && media_impl.notNull())
+ {
+ mMediaImpl = media_impl;
+ LLSelectMgr::getInstance()->deselectAll();
+ LLSelectMgr::getInstance()->selectObjectOnly(objectp, face);
+
+ mFocus = LLSelectMgr::getInstance()->getSelection();
+ if(mMediaHUD.get() && ! parcel->getMediaPreventCameraZoom())
+ {
+ mMediaHUD.get()->resetZoomLevel();
+ mMediaHUD.get()->nextZoomLevel();
+ }
+ if (!mFocus->isEmpty())
+ {
+ gFocusMgr.setKeyboardFocus(this);
+ }
+ mObjectID = objectp->getID();
+ // LLViewerMedia::addObserver(this, mObjectID);
+
+
+ }
+ else
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ mFocus = NULL;
+ if(! parcel->getMediaPreventCameraZoom())
+ {
+ gAgent.setFocusOnAvatar(TRUE, ANIMATE);
+ }
+ // LLViewerMedia::remObserver(this, mObjectID);
+
+ // Null out the media hud media pointer
+ if(mMediaHUD.get())
+ {
+ mMediaHUD.get()->setMediaImpl(NULL);
+ }
+
+ // and null out the media impl
+ mMediaImpl = NULL;
+ }
+ if(mMediaHUD.get())
+ {
+ mMediaHUD.get()->setMediaFocus(b);
+ }
+}
+bool LLViewerMediaFocus::getFocus()
+{
+ if (gFocusMgr.getKeyboardFocus() == this)
+ {
+ return true;
+ }
+ return false;
+}
+
+// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value
+void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
+{
+ LLPickInfo& pick = LLToolPie::getInstance()->getPick();
+
+ if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ pick = mPickInfo;
+ setFocusFace(true, pick.getObject(), pick.mObjectFace, mMediaImpl);
+ }
+
+ if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ gAgent.setFocusOnAvatar(FALSE, ANIMATE);
+
+ LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
+ F32 height;
+ F32 width;
+ F32 depth;
+ F32 angle_of_view;
+ F32 distance;
+
+ // We need the aspect ratio, and the 3 components of the bbox as height, width, and depth.
+ F32 aspect_ratio = getBBoxAspectRatio(selection_bbox, pick.mNormal, &height, &width, &depth);
+ F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();
+
+ // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for
+ // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is
+ // more extreme than the screen. In this case we invert the logic, using the longer component of both the object
+ // and the screen.
+ bool invert = (camera_aspect > 1.0f && aspect_ratio > camera_aspect) ||
+ (camera_aspect < 1.0f && aspect_ratio < camera_aspect);
+
+ // To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle.
+ // In portrait mode this is the width, and in landscape it is the height.
+ // We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape)
+ // We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox.
+ if(camera_aspect < 1.0f || invert)
+ {
+ angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect());
+ distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
+ }
+ else
+ {
+ angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView());
+ distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
+ }
+
+ distance += depth * 0.5;
+
+ // Finally animate the camera to this new position and focal point
+ gAgent.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance),
+ LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID );
+ }
+}
+void LLViewerMediaFocus::onFocusReceived()
+{
+ if(mMediaImpl.notNull())
+ mMediaImpl->focus(true);
+
+ LLFocusableElement::onFocusReceived();
+}
+
+void LLViewerMediaFocus::onFocusLost()
+{
+ if(mMediaImpl.notNull())
+ mMediaImpl->focus(false);
+ gViewerWindow->focusClient();
+ mFocus = NULL;
+ LLFocusableElement::onFocusLost();
+}
+void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl)
+{
+ if (b && media_impl.notNull())
+ {
+ if(! mMediaHUD.get())
+ {
+ LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(mMediaImpl);
+ mMediaHUD = media_hud->getHandle();
+ gHUDView->addChild(media_hud);
+ }
+ mMediaHUD.get()->setMediaImpl(media_impl);
+ mMediaImpl = media_impl;
+ }
+ mMouseOverFlag = b;
+}
+LLUUID LLViewerMediaFocus::getSelectedUUID()
+{
+ LLViewerObject* object = mFocus->getFirstObject();
+ return object ? object->getID() : LLUUID::null;
+}
+#if 0 // Must re-implement when the new media api event system is ready
+void LLViewerMediaFocus::onNavigateComplete( const EventType& event_in )
+{
+ if (hasFocus() && mLastURL != event_in.getStringValue())
+ {
+ LLViewerMedia::focus(true, mObjectID);
+ // spoof mouse event to reassert focus
+ LLViewerMedia::mouseDown(1,1, mObjectID);
+ LLViewerMedia::mouseUp(1,1, mObjectID);
+ }
+ mLastURL = event_in.getStringValue();
+}
+#endif
+BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
+{
+ if(mMediaImpl.notNull())
+ mMediaImpl->handleKeyHere(key, mask);
+ return true;
+}
+
+BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
+{
+ if(mMediaImpl.notNull())
+ mMediaImpl->handleUnicodeCharHere(uni_char);
+ return true;
+}
+BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+ BOOL retval = FALSE;
+ if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia())
+ {
+ mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks);
+ retval = TRUE;
+ }
+ return retval;
+}
+
+void LLViewerMediaFocus::update()
+{
+ if (mMediaHUD.get())
+ {
+ if(mFocus.notNull() || mMouseOverFlag || mMediaHUD.get()->isMouseOver())
+ {
+ // mMediaHUD.get()->setVisible(true);
+ mMediaHUD.get()->updateShape();
+ }
+ else
+ {
+ mMediaHUD.get()->setVisible(false);
+ }
+ }
+}
+// This function calculates the aspect ratio and the world aligned components of a selection bounding box.
+F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth)
+{
+ // Convert the selection normal and an up vector to local coordinate space of the bbox
+ LLVector3 local_normal = bbox.agentToLocalBasis(normal);
+ LLVector3 z_vec = bbox.agentToLocalBasis(LLVector3(0.0f, 0.0f, 1.0f));
+
+ LLVector3 comp1(0.f,0.f,0.f);
+ LLVector3 comp2(0.f,0.f,0.f);
+ LLVector3 bbox_max = bbox.getExtentLocal();
+ F32 dot1 = 0.f;
+ F32 dot2 = 0.f;
+
+ // The largest component of the localized normal vector is the depth component
+ // meaning that the other two are the legs of the rectangle.
+ local_normal.abs();
+ if(local_normal.mV[VX] > local_normal.mV[VY])
+ {
+ if(local_normal.mV[VX] > local_normal.mV[VZ])
+ {
+ // Use the y and z comps
+ comp1.mV[VY] = bbox_max.mV[VY];
+ comp2.mV[VZ] = bbox_max.mV[VZ];
+ *depth = bbox_max.mV[VX];
+ }
+ else
+ {
+ // Use the x and y comps
+ comp1.mV[VY] = bbox_max.mV[VY];
+ comp2.mV[VZ] = bbox_max.mV[VZ];
+ *depth = bbox_max.mV[VZ];
+ }
+ }
+ else if(local_normal.mV[VY] > local_normal.mV[VZ])
+ {
+ // Use the x and z comps
+ comp1.mV[VX] = bbox_max.mV[VX];
+ comp2.mV[VZ] = bbox_max.mV[VZ];
+ *depth = bbox_max.mV[VY];
+ }
+ else
+ {
+ // Use the x and y comps
+ comp1.mV[VY] = bbox_max.mV[VY];
+ comp2.mV[VZ] = bbox_max.mV[VZ];
+ *depth = bbox_max.mV[VX];
+ }
+
+ // The height is the vector closest to vertical in the bbox coordinate space (highest dot product value)
+ dot1 = comp1 * z_vec;
+ dot2 = comp2 * z_vec;
+ if(fabs(dot1) > fabs(dot2))
+ {
+ *height = comp1.length();
+ *width = comp2.length();
+ }
+ else
+ {
+ *height = comp2.length();
+ *width = comp1.length();
+ }
+
+ // Return the aspect ratio.
+ return *width / *height;
+}