diff options
Diffstat (limited to 'linden/indra/newview/llviewermediafocus.cpp')
-rw-r--r-- | linden/indra/newview/llviewermediafocus.cpp | 359 |
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 | |||
55 | LLViewerMediaFocus::LLViewerMediaFocus() | ||
56 | : mMouseOverFlag(false) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | LLViewerMediaFocus::~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 | |||
66 | void 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 | |||
92 | void 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 | } | ||
143 | bool 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 | ||
153 | void 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 | } | ||
207 | void LLViewerMediaFocus::onFocusReceived() | ||
208 | { | ||
209 | if(mMediaImpl.notNull()) | ||
210 | mMediaImpl->focus(true); | ||
211 | |||
212 | LLFocusableElement::onFocusReceived(); | ||
213 | } | ||
214 | |||
215 | void LLViewerMediaFocus::onFocusLost() | ||
216 | { | ||
217 | if(mMediaImpl.notNull()) | ||
218 | mMediaImpl->focus(false); | ||
219 | gViewerWindow->focusClient(); | ||
220 | mFocus = NULL; | ||
221 | LLFocusableElement::onFocusLost(); | ||
222 | } | ||
223 | void 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 | } | ||
238 | LLUUID 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 | ||
244 | void 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 | ||
256 | BOOL 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 | |||
263 | BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) | ||
264 | { | ||
265 | if(mMediaImpl.notNull()) | ||
266 | mMediaImpl->handleUnicodeCharHere(uni_char); | ||
267 | return true; | ||
268 | } | ||
269 | BOOL 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 | |||
280 | void 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. | ||
296 | F32 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 | } | ||