aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewermediafocus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llviewermediafocus.cpp')
-rw-r--r--linden/indra/newview/llviewermediafocus.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewermediafocus.cpp b/linden/indra/newview/llviewermediafocus.cpp
new file mode 100644
index 0000000..2e372a1
--- /dev/null
+++ b/linden/indra/newview/llviewermediafocus.cpp
@@ -0,0 +1,359 @@
1/**
2 * @file llviewermediafocus.cpp
3 * @brief Governs focus on Media prims
4 *
5 * $LicenseInfo:firstyear=2003&license=viewergpl$
6 *
7 * Copyright (c) 2003-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "llviewermediafocus.h"
36
37//LLViewerMediaFocus
38#include "llviewerobjectlist.h"
39#include "llpanelmediahud.h"
40#include "llpluginclassmedia.h"
41#include "llagent.h"
42#include "lltoolpie.h"
43#include "llviewercamera.h"
44#include "llviewermedia.h"
45#include "llhudview.h"
46#include "lluictrlfactory.h"
47#include "lldrawable.h"
48#include "llparcel.h"
49#include "llviewerparcelmgr.h"
50#include "llweb.h"
51//
52// LLViewerMediaFocus
53//
54
55LLViewerMediaFocus::LLViewerMediaFocus()
56: mMouseOverFlag(false)
57{
58}
59
60LLViewerMediaFocus::~LLViewerMediaFocus()
61{
62 // The destructor for LLSingletons happens at atexit() time, which is too late to do much.
63 // Clean up in cleanupClass() instead.
64}
65
66void LLViewerMediaFocus::cleanupClass()
67{
68 LLViewerMediaFocus *self = LLViewerMediaFocus::getInstance();
69
70 if(self)
71 {
72 // mMediaHUD will have been deleted by this point -- don't try to delete it.
73
74 /* Richard says:
75 all widgets are supposed to be destroyed at the same time
76 you shouldn't hold on to pointer to them outside of ui code
77 you can use the LLHandle approach
78 if you want to be type safe, you'll need to add a LLRootHandle to whatever derived class you are pointing to
79 look at llview::gethandle
80 its our version of a weak pointer
81 */
82 if(self->mMediaHUD.get())
83 {
84 self->mMediaHUD.get()->setMediaImpl(NULL);
85 }
86 self->mMediaImpl = NULL;
87 }
88
89}
90
91
92void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl )
93{
94 LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
95 if (b && media_impl.notNull())
96 {
97 mMediaImpl = media_impl;
98 LLSelectMgr::getInstance()->deselectAll();
99 LLSelectMgr::getInstance()->selectObjectOnly(objectp, face);
100
101 mFocus = LLSelectMgr::getInstance()->getSelection();
102 if(mMediaHUD.get() && ! parcel->getMediaPreventCameraZoom())
103 {
104 mMediaHUD.get()->resetZoomLevel();
105 mMediaHUD.get()->nextZoomLevel();
106 }
107 if (!mFocus->isEmpty())
108 {
109 gFocusMgr.setKeyboardFocus(this);
110 }
111 mObjectID = objectp->getID();
112 // LLViewerMedia::addObserver(this, mObjectID);
113
114
115 }
116 else
117 {
118 gFocusMgr.setKeyboardFocus(NULL);
119 if(! parcel->getMediaPreventCameraZoom())
120 {
121 if (!mFocus->isEmpty())
122 {
123 gAgent.setFocusOnAvatar(TRUE, ANIMATE);
124 }
125 }
126 mFocus = NULL;
127 // LLViewerMedia::remObserver(this, mObjectID);
128
129 // Null out the media hud media pointer
130 if(mMediaHUD.get())
131 {
132 mMediaHUD.get()->setMediaImpl(NULL);
133 }
134
135 // and null out the media impl
136 mMediaImpl = NULL;
137 }
138 if(mMediaHUD.get())
139 {
140 mMediaHUD.get()->setMediaFocus(b);
141 }
142}
143bool LLViewerMediaFocus::getFocus()
144{
145 if (gFocusMgr.getKeyboardFocus() == this)
146 {
147 return true;
148 }
149 return false;
150}
151
152// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value
153void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
154{
155 LLPickInfo& pick = LLToolPie::getInstance()->getPick();
156
157 if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
158 {
159 pick = mPickInfo;
160 setFocusFace(true, pick.getObject(), pick.mObjectFace, mMediaImpl);
161 }
162
163 if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
164 {
165 gAgent.setFocusOnAvatar(FALSE, ANIMATE);
166
167 LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
168 F32 height;
169 F32 width;
170 F32 depth;
171 F32 angle_of_view;
172 F32 distance;
173
174 // We need the aspect ratio, and the 3 components of the bbox as height, width, and depth.
175 F32 aspect_ratio = getBBoxAspectRatio(selection_bbox, pick.mNormal, &height, &width, &depth);
176 F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();
177
178 // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for
179 // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is
180 // more extreme than the screen. In this case we invert the logic, using the longer component of both the object
181 // and the screen.
182 bool invert = (camera_aspect > 1.0f && aspect_ratio > camera_aspect) ||
183 (camera_aspect < 1.0f && aspect_ratio < camera_aspect);
184
185 // To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle.
186 // In portrait mode this is the width, and in landscape it is the height.
187 // We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape)
188 // We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox.
189 if(camera_aspect < 1.0f || invert)
190 {
191 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect());
192 distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
193 }
194 else
195 {
196 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView());
197 distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
198 }
199
200 distance += depth * 0.5;
201
202 // Finally animate the camera to this new position and focal point
203 gAgent.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance),
204 LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID );
205 }
206}
207void LLViewerMediaFocus::onFocusReceived()
208{
209 if(mMediaImpl.notNull())
210 mMediaImpl->focus(true);
211
212 LLFocusableElement::onFocusReceived();
213}
214
215void LLViewerMediaFocus::onFocusLost()
216{
217 if(mMediaImpl.notNull())
218 mMediaImpl->focus(false);
219 gViewerWindow->focusClient();
220 mFocus = NULL;
221 LLFocusableElement::onFocusLost();
222}
223void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl)
224{
225 if (b && media_impl.notNull())
226 {
227 if(! mMediaHUD.get())
228 {
229 LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(mMediaImpl);
230 mMediaHUD = media_hud->getHandle();
231 gHUDView->addChild(media_hud);
232 }
233 mMediaHUD.get()->setMediaImpl(media_impl);
234 mMediaImpl = media_impl;
235 }
236 mMouseOverFlag = b;
237}
238LLUUID LLViewerMediaFocus::getSelectedUUID()
239{
240 LLViewerObject* object = mFocus->getFirstObject();
241 return object ? object->getID() : LLUUID::null;
242}
243#if 0 // Must re-implement when the new media api event system is ready
244void LLViewerMediaFocus::onNavigateComplete( const EventType& event_in )
245{
246 if (hasFocus() && mLastURL != event_in.getStringValue())
247 {
248 LLViewerMedia::focus(true, mObjectID);
249 // spoof mouse event to reassert focus
250 LLViewerMedia::mouseDown(1,1, mObjectID);
251 LLViewerMedia::mouseUp(1,1, mObjectID);
252 }
253 mLastURL = event_in.getStringValue();
254}
255#endif
256BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent)
257{
258 if(mMediaImpl.notNull())
259 mMediaImpl->handleKeyHere(key, mask);
260 return true;
261}
262
263BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
264{
265 if(mMediaImpl.notNull())
266 mMediaImpl->handleUnicodeCharHere(uni_char);
267 return true;
268}
269BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks)
270{
271 BOOL retval = FALSE;
272 if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia())
273 {
274 mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks);
275 retval = TRUE;
276 }
277 return retval;
278}
279
280void LLViewerMediaFocus::update()
281{
282 if (mMediaHUD.get())
283 {
284 if(mFocus.notNull() || mMouseOverFlag || mMediaHUD.get()->isMouseOver())
285 {
286 // mMediaHUD.get()->setVisible(true);
287 mMediaHUD.get()->updateShape();
288 }
289 else
290 {
291 mMediaHUD.get()->setVisible(false);
292 }
293 }
294}
295// This function calculates the aspect ratio and the world aligned components of a selection bounding box.
296F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth)
297{
298 // Convert the selection normal and an up vector to local coordinate space of the bbox
299 LLVector3 local_normal = bbox.agentToLocalBasis(normal);
300 LLVector3 z_vec = bbox.agentToLocalBasis(LLVector3(0.0f, 0.0f, 1.0f));
301
302 LLVector3 comp1(0.f,0.f,0.f);
303 LLVector3 comp2(0.f,0.f,0.f);
304 LLVector3 bbox_max = bbox.getExtentLocal();
305 F32 dot1 = 0.f;
306 F32 dot2 = 0.f;
307
308 // The largest component of the localized normal vector is the depth component
309 // meaning that the other two are the legs of the rectangle.
310 local_normal.abs();
311 if(local_normal.mV[VX] > local_normal.mV[VY])
312 {
313 if(local_normal.mV[VX] > local_normal.mV[VZ])
314 {
315 // Use the y and z comps
316 comp1.mV[VY] = bbox_max.mV[VY];
317 comp2.mV[VZ] = bbox_max.mV[VZ];
318 *depth = bbox_max.mV[VX];
319 }
320 else
321 {
322 // Use the x and y comps
323 comp1.mV[VY] = bbox_max.mV[VY];
324 comp2.mV[VZ] = bbox_max.mV[VZ];
325 *depth = bbox_max.mV[VZ];
326 }
327 }
328 else if(local_normal.mV[VY] > local_normal.mV[VZ])
329 {
330 // Use the x and z comps
331 comp1.mV[VX] = bbox_max.mV[VX];
332 comp2.mV[VZ] = bbox_max.mV[VZ];
333 *depth = bbox_max.mV[VY];
334 }
335 else
336 {
337 // Use the x and y comps
338 comp1.mV[VY] = bbox_max.mV[VY];
339 comp2.mV[VZ] = bbox_max.mV[VZ];
340 *depth = bbox_max.mV[VX];
341 }
342
343 // The height is the vector closest to vertical in the bbox coordinate space (highest dot product value)
344 dot1 = comp1 * z_vec;
345 dot2 = comp2 * z_vec;
346 if(fabs(dot1) > fabs(dot2))
347 {
348 *height = comp1.length();
349 *width = comp2.length();
350 }
351 else
352 {
353 *height = comp2.length();
354 *width = comp1.length();
355 }
356
357 // Return the aspect ratio.
358 return *width / *height;
359}