From 2cb043a6262e61809c26496a6ec197179806e0d4 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 15 Oct 2009 16:30:48 -0700 Subject: FIX DEV-39513: Tweak target camera position to avoid a flip when target normal is vertical Review #21 This attempts to tweak the target camera position slightly towards where the camera started from, so as to avoid the flip noted in this JIRA. --- indra/newview/llviewermediafocus.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'indra/newview/llviewermediafocus.cpp') diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index db31714f16..74ed6eea7b 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -227,8 +227,27 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) 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 ); + LLVector3d camera_pos, target_pos; + // Target lookat position is the center of the selection (in global coords) + target_pos = LLSelectMgr::getInstance()->getSelectionCenterGlobal(); + // Target look-from (camera) position is "distance" away from the target along the normal + LLVector3d pickNormal = LLVector3d(pick.mNormal); + pickNormal.normalize(); + camera_pos = target_pos + pickNormal * distance; + if (pickNormal == LLVector3d::z_axis || pickNormal == LLVector3d::z_axis_neg) + { + // If the normal points directly up, the camera will "flip" around. + // We try to avoid this by adjusting the target camera position a + // smidge towards current camera position + LLVector3d cur_camera_pos = LLVector3d(gAgent.getCameraPositionGlobal()); + LLVector3d delta = (cur_camera_pos - camera_pos); + F64 len = delta.length(); + delta.normalize(); + // Move 1% of the distance towards original camera location + camera_pos += 0.01 * len * delta; + } + + gAgent.setCameraPosAndFocusGlobal(camera_pos, target_pos, LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID ); } } void LLViewerMediaFocus::onFocusReceived() -- cgit v1.2.3 From 665bac16cef36e265829d6692959daacc9811451 Mon Sep 17 00:00:00 2001 From: Rick Pasetto Date: Thu, 15 Oct 2009 17:33:42 -0700 Subject: Clarify comments a little --- indra/newview/llviewermediafocus.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'indra/newview/llviewermediafocus.cpp') diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index 74ed6eea7b..d81c332d54 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -228,7 +228,7 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) // Finally animate the camera to this new position and focal point LLVector3d camera_pos, target_pos; - // Target lookat position is the center of the selection (in global coords) + // The target lookat position is the center of the selection (in global coords) target_pos = LLSelectMgr::getInstance()->getSelectionCenterGlobal(); // Target look-from (camera) position is "distance" away from the target along the normal LLVector3d pickNormal = LLVector3d(pick.mNormal); @@ -239,6 +239,14 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) // If the normal points directly up, the camera will "flip" around. // We try to avoid this by adjusting the target camera position a // smidge towards current camera position + // *NOTE: this solution is not perfect. All it attempts to solve is the + // "looking down" problem where the camera flips around when it animates + // to that position. You still are not guaranteed to be looking at the + // media in the correct orientation. What this solution does is it will + // put the camera into position keeping as best it can the current + // orientation with respect to the face. In other words, if before zoom + // the media appears "upside down" from the camera, after zooming it will + // still be upside down, but at least it will not flip. LLVector3d cur_camera_pos = LLVector3d(gAgent.getCameraPositionGlobal()); LLVector3d delta = (cur_camera_pos - camera_pos); F64 len = delta.length(); -- cgit v1.2.3 From 86787b58edf59997b68dca6a0927d24b2a24a2b5 Mon Sep 17 00:00:00 2001 From: Monroe Linden Date: Thu, 15 Oct 2009 18:42:30 -0700 Subject: Major refactor of LLViewerMediaFocus and LLPanelMediaHUD. LLViewerMediaFocus now tracks two separate objects: the currently focused media object, and the media object that's currently being hovered over. It no longer stores smart pointers to either the LLViewerObject or the LLViewerMediaImpl -- it now looks up both by UUID every time they're needed, and fails gracefully if either goes away. This will prevent it from keeping objects from being deleted. The poorly-understood "mouseOverFlag" has been expunged. LLViewerMediaFocus no longer uses LLSelectMgr at all. The object to focus on is explicitly passed between LLViewerMediaFocus and LLPanelMediaHUD instead of going indirectly through the selection manager. LLViewerMediaFocus also no longer interacts with the pick from LLToolPie -- the data it needs from the pick (the object and normal vector) is passed explicitly. LLViewerMediaFocus::setCameraZoom and LLViewerMediaFocus::getBBoxAspectRatio now have no dependencies on the LLViewerMediaFocus object -- all the data they need is passed in when they're called by the LLPanelMediaHUD. I made them static member functions, but they could be moved to LLPanelMediaHUD or even made into file-scoped static functions. The only reason I didn't do either of those is that it seems like they belong with the LLViewerMediaFocus code as opposed to the HUD. --- indra/newview/llviewermediafocus.cpp | 303 ++++++++++++++++++----------------- 1 file changed, 158 insertions(+), 145 deletions(-) (limited to 'indra/newview/llviewermediafocus.cpp') diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index d81c332d54..cad8b5f0ce 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -53,7 +53,8 @@ // LLViewerMediaFocus::LLViewerMediaFocus() -: mMouseOverFlag(false) +: mFocusedObjectFace(0), + mHoverObjectFace(0) { } @@ -63,110 +64,100 @@ LLViewerMediaFocus::~LLViewerMediaFocus() // 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 objectp, S32 face, viewer_media_t media_impl ) -{ +void LLViewerMediaFocus::setFocusFace(LLPointer objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal) +{ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - - if(mMediaImpl.notNull()) + + LLViewerMediaImpl *old_media_impl = getFocusedMediaImpl(); + if(old_media_impl) { - mMediaImpl->focus(false); + old_media_impl->focus(false); } - if (b && media_impl.notNull()) + if (media_impl.notNull() && objectp.notNull()) { bool face_auto_zoom = false; - mMediaImpl = media_impl; - mMediaImpl->focus(true); + media_impl->focus(true); - LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->selectObjectOnly(objectp, face); + mFocusedImplID = media_impl->getMediaTextureID(); + mFocusedObjectID = objectp->getID(); + mFocusedObjectFace = face; + mFocusedObjectNormal = pick_normal; - if(objectp.notNull()) + LLTextureEntry* tep = objectp->getTE(face); + if(tep->hasMedia()) { - LLTextureEntry* tep = objectp->getTE(face); - if(! tep->hasMedia()) - { - // Error condition - } LLMediaEntry* mep = tep->getMediaData(); face_auto_zoom = mep->getAutoZoom(); - if(! mep->getAutoPlay()) + if(!media_impl->hasMedia()) { std::string url = mep->getCurrentURL().empty() ? mep->getHomeURL() : mep->getCurrentURL(); media_impl->navigateTo(url, "", true); } } - mFocus = LLSelectMgr::getInstance()->getSelection(); + else + { + // This should never happen. + llwarns << "Can't find media entry for focused face" << llendl; + } + + gFocusMgr.setKeyboardFocus(this); + + // We must do this before processing the media HUD zoom, or it may zoom to the wrong face. + update(); + if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom()) { mMediaHUD.get()->resetZoomLevel(); mMediaHUD.get()->nextZoomLevel(); } - if (!mFocus->isEmpty()) - { - gFocusMgr.setKeyboardFocus(this); - } - mObjectID = objectp->getID(); - mObjectFace = face; - // LLViewerMedia::addObserver(this, mObjectID); - - } else { - gFocusMgr.setKeyboardFocus(NULL); - if(! parcel->getMediaPreventCameraZoom()) + if(hasFocus()) { - if (!mFocus->isEmpty()) + if(mMediaHUD.get()) { - gAgent.setFocusOnAvatar(TRUE, ANIMATE); + mMediaHUD.get()->resetZoomLevel(); } + + gFocusMgr.setKeyboardFocus(NULL); } - mFocus = NULL; - // LLViewerMedia::remObserver(this, mObjectID); - // Null out the media hud media pointer - if(mMediaHUD.get()) - { - mMediaHUD.get()->setMediaImpl(NULL); - } + mFocusedImplID = LLUUID::null; + mFocusedObjectID = LLUUID::null; + mFocusedObjectFace = 0; + } +} - // and null out the media impl - mMediaImpl = NULL; - mObjectID = LLUUID::null; - mObjectFace = 0; +void LLViewerMediaFocus::clearFocus() +{ + setFocusFace(NULL, 0, NULL); +} + +void LLViewerMediaFocus::setHoverFace(LLPointer objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal) +{ + if (media_impl.notNull()) + { + mHoverImplID = media_impl->getMediaTextureID(); + mHoverObjectID = objectp->getID(); + mHoverObjectFace = face; + mHoverObjectNormal = pick_normal; } - if(mMediaHUD.get()) + else { - mMediaHUD.get()->setMediaFocus(b); + mHoverObjectID = LLUUID::null; + mHoverObjectFace = 0; + mHoverImplID = LLUUID::null; } } + +void LLViewerMediaFocus::clearHover() +{ + setHoverFace(NULL, 0, NULL); +} + + bool LLViewerMediaFocus::getFocus() { if (gFocusMgr.getKeyboardFocus() == this) @@ -176,22 +167,15 @@ bool LLViewerMediaFocus::getFocus() return false; } -// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value -void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) +// This function selects an ideal viewing distance based on the focused object, pick normal, and padding value +void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, 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()) + if (object) { gAgent.setFocusOnAvatar(FALSE, ANIMATE); - LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + LLBBox bbox = object->getBoundingBoxAgent(); + LLVector3d center = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); F32 height; F32 width; F32 depth; @@ -199,7 +183,7 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) 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 aspect_ratio = getBBoxAspectRatio(bbox, normal, &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 @@ -229,9 +213,9 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) // Finally animate the camera to this new position and focal point LLVector3d camera_pos, target_pos; // The target lookat position is the center of the selection (in global coords) - target_pos = LLSelectMgr::getInstance()->getSelectionCenterGlobal(); + target_pos = center; // Target look-from (camera) position is "distance" away from the target along the normal - LLVector3d pickNormal = LLVector3d(pick.mNormal); + LLVector3d pickNormal = LLVector3d(normal); pickNormal.normalize(); camera_pos = target_pos + pickNormal * distance; if (pickNormal == LLVector3d::z_axis || pickNormal == LLVector3d::z_axis_neg) @@ -255,92 +239,69 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) camera_pos += 0.01 * len * delta; } - gAgent.setCameraPosAndFocusGlobal(camera_pos, target_pos, LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID ); + gAgent.setCameraPosAndFocusGlobal(camera_pos, target_pos, object->getID() ); + } + else + { + // If we have no object, focus back on the avatar. + gAgent.setFocusOnAvatar(TRUE, ANIMATE); } } void LLViewerMediaFocus::onFocusReceived() { - if(mMediaImpl.notNull()) - mMediaImpl->focus(true); + // Don't do this here -- this doesn't change "inworld media focus", it just changes whether the viewer's input is focused on the media. +// LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); +// if(media_impl.notNull()) +// media_impl->focus(true); LLFocusableElement::onFocusReceived(); } void LLViewerMediaFocus::onFocusLost() { - if(mMediaImpl.notNull()) - mMediaImpl->focus(false); + // Don't do this here -- this doesn't change "inworld media focus", it just changes whether the viewer's input is focused on the media. +// LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); +// if(media_impl.notNull()) +// media_impl->focus(false); + gViewerWindow->focusClient(); - mFocus = NULL; LLFocusableElement::onFocusLost(); } -void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl) + +BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent) { - if (b && media_impl.notNull()) + LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); + if(media_impl) { - if(! mMediaHUD.get()) - { - LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(mMediaImpl); - mMediaHUD = media_hud->getHandle(); - gHUDView->addChild(media_hud); - } - mMediaHUD.get()->setMediaImpl(media_impl); + media_impl->handleKeyHere(key, mask); - if(mMediaImpl.notNull() && (mMediaImpl != media_impl)) + if (key == KEY_ESCAPE) { - mMediaImpl->focus(false); + clearFocus(); } - - 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); - - if (key == KEY_ESCAPE && mMediaHUD.get()) - { - mMediaHUD.get()->close(); } + return true; } BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { - if(mMediaImpl.notNull()) - mMediaImpl->handleUnicodeCharHere(uni_char); + LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); + if(media_impl) + media_impl->handleUnicodeCharHere(uni_char); return true; } BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) { BOOL retval = FALSE; - if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia()) + LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); + if(media_impl && media_impl->hasMedia()) { // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y. // The latter is the position of the mouse at the time of the event // The former is the 'scroll amount' in x and y, respectively. // All we have for 'scroll amount' here is 'clicks', and no mask. - mMediaImpl->getMediaPlugin()->scrollEvent(0, clicks, /*mask*/0); + media_impl->getMediaPlugin()->scrollEvent(0, clicks, /*mask*/0); retval = TRUE; } return retval; @@ -348,19 +309,45 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) void LLViewerMediaFocus::update() { - if (mMediaHUD.get()) + LLViewerMediaImpl *media_impl = getFocusedMediaImpl(); + LLViewerObject *viewer_object = getFocusedObject(); + S32 face = mFocusedObjectFace; + LLVector3 normal = mFocusedObjectNormal; + bool focus = true; + + if(!media_impl || !viewer_object) + { + focus = false; + media_impl = getHoverMediaImpl(); + viewer_object = getHoverObject(); + face = mHoverObjectFace; + normal = mHoverObjectNormal; + } + + if(media_impl && viewer_object) { - if(mFocus.notNull() || mMouseOverFlag || mMediaHUD.get()->isMouseOver()) + // We have an object and impl to point at. + + // Make sure the media HUD object exists. + if(! mMediaHUD.get()) { - // mMediaHUD.get()->setVisible(true); - mMediaHUD.get()->updateShape(); + LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(); + mMediaHUD = media_hud->getHandle(); + gHUDView->addChild(media_hud); } - else + mMediaHUD.get()->setMediaFace(viewer_object, face, media_impl, normal); + } + else + { + // The media HUD is no longer needed. + if(mMediaHUD.get()) { - mMediaHUD.get()->setVisible(false); + mMediaHUD.get()->setMediaFace(NULL, 0, NULL); } } } + + // 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) { @@ -429,5 +416,31 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& bool LLViewerMediaFocus::isFocusedOnFace(LLPointer objectp, S32 face) { - return objectp->getID() == mObjectID && face == mObjectFace; + return objectp->getID() == mFocusedObjectID && face == mFocusedObjectFace; +} + +bool LLViewerMediaFocus::isHoveringOverFace(LLPointer objectp, S32 face) +{ + return objectp->getID() == mHoverObjectID && face == mHoverObjectFace; +} + + +LLViewerMediaImpl* LLViewerMediaFocus::getFocusedMediaImpl() +{ + return LLViewerMedia::getMediaImplFromTextureID(mFocusedImplID); +} + +LLViewerObject* LLViewerMediaFocus::getFocusedObject() +{ + return gObjectList.findObject(mFocusedObjectID); +} + +LLViewerMediaImpl* LLViewerMediaFocus::getHoverMediaImpl() +{ + return LLViewerMedia::getMediaImplFromTextureID(mHoverImplID); +} + +LLViewerObject* LLViewerMediaFocus::getHoverObject() +{ + return gObjectList.findObject(mHoverObjectID); } -- cgit v1.2.3