diff options
Diffstat (limited to 'indra/newview/llnetmap.cpp')
-rwxr-xr-x[-rw-r--r--] | indra/newview/llnetmap.cpp | 657 |
1 files changed, 479 insertions, 178 deletions
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index b6b433c28f..d7e7f13e87 100644..100755 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -3,31 +3,25 @@ * @author James Cook * @brief Display of surrounding regions, objects, and agents. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2001-2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * 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://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,6 +31,7 @@ // Library includes (should move below) #include "indra_constants.h" +#include "llavatarnamecache.h" #include "llmath.h" #include "llfloaterreg.h" #include "llfocusmgr.h" @@ -49,8 +44,10 @@ // Viewer includes #include "llagent.h" +#include "llagentcamera.h" #include "llappviewer.h" // for gDisconnected #include "llcallingcard.h" // LLAvatarTracker +#include "llfloaterworldmap.h" #include "lltracker.h" #include "llsurface.h" #include "llviewercamera.h" @@ -60,14 +57,23 @@ #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" +#include "llviewerwindow.h" #include "llworld.h" #include "llworldmapview.h" // shared draw code static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map"); -const F32 MAP_SCALE_INCREMENT = 16; -const F32 MAP_MIN_PICK_DIST = 4; -const F32 MAX_PRIM_RADIUS = 256.0f; // Don't try to draw giant mega-prims on the mini map +const F32 LLNetMap::MAP_SCALE_MIN = 32; +const F32 LLNetMap::MAP_SCALE_MID = 1024; +const F32 LLNetMap::MAP_SCALE_MAX = 4096; + +const F32 MAP_SCALE_ZOOM_FACTOR = 1.04f; // Zoom in factor per click of scroll wheel (4%) +const F32 MIN_DOT_RADIUS = 3.5f; +const F32 DOT_SCALE = 0.75f; +const F32 MIN_PICK_SCALE = 2.f; +const S32 MOUSE_DRAG_SLOP = 2; // How far the mouse needs to move before we think it's a drag + +const F64 COARSEUPDATE_MAX_Z = 1020.0f; LLNetMap::LLNetMap (const Params & p) : LLUICtrl (p), @@ -76,50 +82,62 @@ LLNetMap::LLNetMap (const Params & p) mPixelsPerMeter( MAP_SCALE_MID / REGION_WIDTH_METERS ), mObjectMapTPM(0.f), mObjectMapPixels(0.f), - mTargetPanX(0.f), - mTargetPanY(0.f), - mCurPanX(0.f), - mCurPanY(0.f), - mUpdateNow(FALSE), - mObjectImageCenterGlobal( gAgent.getCameraPositionGlobal() ), + mTargetPan(0.f, 0.f), + mCurPan(0.f, 0.f), + mStartPan(0.f, 0.f), + mMouseDown(0, 0), + mPanning(false), + mUpdateNow(false), + mObjectImageCenterGlobal( gAgentCamera.getCameraPositionGlobal() ), mObjectRawImagep(), mObjectImagep(), mClosestAgentToCursor(), mClosestAgentAtLastRightClick(), - mRotateMap(FALSE), - mToolTipMsg() + mToolTipMsg(), + mPopupMenu(NULL) { + mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); + setScale(gSavedSettings.getF32("MiniMapScale")); } LLNetMap::~LLNetMap() { + gSavedSettings.setF32("MiniMapScale", mScale); +} + +BOOL LLNetMap::postBuild() +{ + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2)); + registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2)); + + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + return TRUE; } void LLNetMap::setScale( F32 scale ) { - mScale = llclamp(scale, 0.1f, 16.f*1024.f); // [reasonably small , unreasonably large] + scale = llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX); + mCurPan *= scale / mScale; + mScale = scale; if (mObjectImagep.notNull()) { - F32 half_width = (F32)(getRect().getWidth() / 2); - F32 half_height = (F32)(getRect().getHeight() / 2); - F32 radius = sqrt( half_width * half_width + half_height * half_height ); - F32 region_widths = (2.f*radius)/mScale; + F32 width = (F32)(getRect().getWidth()); + F32 height = (F32)(getRect().getHeight()); + F32 diameter = sqrt(width * width + height * height); + F32 region_widths = diameter / mScale; F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters(); F32 num_pixels = (F32)mObjectImagep->getWidth(); - mObjectMapTPM = num_pixels/meters; - mObjectMapPixels = 2.f*radius; + mObjectMapTPM = num_pixels / meters; + mObjectMapPixels = diameter; } mPixelsPerMeter = mScale / REGION_WIDTH_METERS; + mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); - mUpdateNow = TRUE; -} - -void LLNetMap::translatePan( F32 delta_x, F32 delta_y ) -{ - mTargetPanX += delta_x; - mTargetPanY += delta_y; + mUpdateNow = true; } @@ -131,7 +149,7 @@ void LLNetMap::draw() static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white); static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); - static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white); + //static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white); static LLUIColor map_frustum_color = LLUIColorTable::instance().getColor("MapFrustumColor", LLColor4::white); static LLUIColor map_frustum_rotating_color = LLUIColorTable::instance().getColor("MapFrustumRotatingColor", LLColor4::white); @@ -139,21 +157,34 @@ void LLNetMap::draw() { createObjectImage(); } - - mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); - mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); + + static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true); + if (auto_center) + { + mCurPan = lerp(mCurPan, mTargetPan, LLSmoothInterpolation::getInterpolant(0.1f)); + } // Prepare a scissor region F32 rotation = 0; + gGL.pushMatrix(); + gGL.pushUIMatrix(); + + LLVector3 offset = gGL.getUITranslation(); + LLVector3 scale = gGL.getUIScale(); + + gGL.loadIdentity(); + gGL.loadUIIdentity(); + + gGL.scalef(scale.mV[0], scale.mV[1], scale.mV[2]); + gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); + { - LLGLEnable scissor(GL_SCISSOR_TEST); - + LLLocalClipRect clip(getLocalRect()); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLLocalClipRect clip(getLocalRect()); - glMatrixMode(GL_MODELVIEW); + gGL.matrixMode(LLRender::MM_MODELVIEW); // Draw background rectangle LLColor4 background_color = mBackgroundColor.get(); @@ -162,22 +193,23 @@ void LLNetMap::draw() } // region 0,0 is in the middle - S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPanX); - S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPanY); + S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPan.mV[VX]); + S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPan.mV[VY]); gGL.pushMatrix(); gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f); - if( mRotateMap ) + static LLUICachedControl<bool> rotate_map("MiniMapRotate", true); + if( rotate_map ) { // rotate subsequent draws to agent rotation rotation = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); - glRotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f); + gGL.rotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f); } // figure out where agent is - S32 region_width = llround(LLWorld::getInstance()->getRegionWidthInMeters()); + S32 region_width = ll_round(LLWorld::getInstance()->getRegionWidthInMeters()); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -185,7 +217,7 @@ void LLNetMap::draw() LLViewerRegion* regionp = *iter; // Find x and y position relative to camera's center. LLVector3 origin_agent = regionp->getOriginAgent(); - LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent(); + LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent(); F32 relative_x = (rel_region_pos.mV[0] / region_width) * mScale; F32 relative_y = (rel_region_pos.mV[1] / region_width) * mScale; @@ -243,26 +275,24 @@ void LLNetMap::draw() } gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } - - - LLVector3d old_center = mObjectImageCenterGlobal; - LLVector3d new_center = gAgent.getCameraPositionGlobal(); - - new_center.mdV[0] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[0]); - new_center.mdV[1] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[1]); - new_center.mdV[2] = 0.f; + // Redraw object layer periodically if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f)) { - mUpdateNow = FALSE; - mObjectImageCenterGlobal = new_center; + mUpdateNow = false; + + // Locate the centre of the object layer, accounting for panning + LLVector3 new_center = globalPosToView(gAgentCamera.getCameraPositionGlobal()); + new_center.mV[VX] -= mCurPan.mV[VX]; + new_center.mV[VY] -= mCurPan.mV[VY]; + new_center.mV[VZ] = 0.f; + mObjectImageCenterGlobal = viewPosToGlobal(llfloor(new_center.mV[VX]), llfloor(new_center.mV[VY])); - // Center moved enough. // Create the base texture. U8 *default_texture = mObjectRawImagep->getData(); memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() ); - // Draw buildings + // Draw objects gObjectList.renderObjectsForMap(*this); mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight()); @@ -271,7 +301,8 @@ void LLNetMap::draw() } LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal); - map_center_agent -= gAgent.getCameraPositionAgent(); + LLVector3 camera_position = gAgentCamera.getCameraPositionAgent(); + map_center_agent -= camera_position; map_center_agent.mV[VX] *= mScale/region_width; map_center_agent.mV[VY] *= mScale/region_width; @@ -292,68 +323,80 @@ void LLNetMap::draw() gGL.popMatrix(); - LLVector3d pos_global; - LLVector3 pos_map; - // Mouse pointer in local coordinates S32 local_mouse_x; S32 local_mouse_y; //localMouse(&local_mouse_x, &local_mouse_y); LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); mClosestAgentToCursor.setNull(); - F32 closest_dist = F32_MAX; + F32 closest_dist_squared = F32_MAX; // value will be overridden in the loop + F32 min_pick_dist_squared = (mDotRadius * MIN_PICK_SCALE) * (mDotRadius * MIN_PICK_SCALE); + + LLVector3 pos_map; + uuid_vec_t avatar_ids; + std::vector<LLVector3d> positions; + bool unknown_relative_z; + + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgentCamera.getCameraPositionGlobal()); // Draw avatars - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + for (U32 i = 0; i < avatar_ids.size(); i++) { - LLViewerRegion* regionp = *iter; - const LLVector3d& origin_global = regionp->getOriginGlobal(); - - S32 count = regionp->mMapAvatars.count(); - S32 i; - LLVector3 pos_local; - U32 compact_local; - U8 bits; - // TODO: it'd be very cool to draw these in sorted order from lowest Z to highest. - // just be careful to sort the avatar IDs along with the positions. -MG - for (i = 0; i < count; i++) - { - compact_local = regionp->mMapAvatars.get(i); + LLUUID uuid = avatar_ids[i]; + // Skip self, we'll draw it later + if (uuid == gAgent.getID()) continue; - bits = compact_local & 0xFF; - pos_local.mV[VZ] = F32(bits) * 4.f; - compact_local >>= 8; + pos_map = globalPosToView(positions[i]); - bits = compact_local & 0xFF; - pos_local.mV[VY] = (F32)bits; - compact_local >>= 8; + bool show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL); - bits = compact_local & 0xFF; - pos_local.mV[VX] = (F32)bits; + LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color; - pos_global.setVec( pos_local ); - pos_global += origin_global; + unknown_relative_z = positions[i].mdV[VZ] == COARSEUPDATE_MAX_Z && + camera_position.mV[VZ] >= COARSEUPDATE_MAX_Z; - pos_map = globalPosToView(pos_global); + LLWorldMapView::drawAvatar( + pos_map.mV[VX], pos_map.mV[VY], + color, + pos_map.mV[VZ], mDotRadius, + unknown_relative_z); - BOOL show_as_friend = FALSE; - if( i < regionp->mMapAvatarIDs.count()) + if(uuid.notNull()) + { + bool selected = false; + uuid_vec_t::iterator sel_iter = gmSelected.begin(); + for (; sel_iter != gmSelected.end(); sel_iter++) { - show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL); + if(*sel_iter == uuid) + { + selected = true; + break; + } } - LLWorldMapView::drawAvatar( - pos_map.mV[VX], pos_map.mV[VY], - show_as_friend ? map_avatar_friend_color : map_avatar_color, - pos_map.mV[VZ]); - - F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); - if(dist_to_cursor < MAP_MIN_PICK_DIST && dist_to_cursor < closest_dist) + if(selected) { - closest_dist = dist_to_cursor; - mClosestAgentToCursor = regionp->mMapAvatarIDs.get(i); + if( (pos_map.mV[VX] < 0) || + (pos_map.mV[VY] < 0) || + (pos_map.mV[VX] >= getRect().getWidth()) || + (pos_map.mV[VY] >= getRect().getHeight()) ) + { + S32 x = ll_round( pos_map.mV[VX] ); + S32 y = ll_round( pos_map.mV[VY] ); + LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10); + } else + { + LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f); + } } } + + F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), + LLVector2(local_mouse_x,local_mouse_y)); + if(dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared) + { + closest_dist_squared = dist_to_cursor_squared; + mClosestAgentToCursor = uuid; + } } // Draw dot for autopilot target @@ -376,12 +419,24 @@ void LLNetMap::draw() } // Draw dot for self avatar position - pos_global = gAgent.getPositionGlobal(); + LLVector3d pos_global = gAgent.getPositionGlobal(); pos_map = globalPosToView(pos_global); - LLUIImagePtr you = LLWorldMapView::sAvatarYouSmallImage; - you->draw( - llround(pos_map.mV[VX]) - you->getWidth()/2, - llround(pos_map.mV[VY]) - you->getHeight()/2); + S32 dot_width = ll_round(mDotRadius * 2.f); + LLUIImagePtr you = LLWorldMapView::sAvatarYouLargeImage; + if (you) + { + you->draw(ll_round(pos_map.mV[VX] - mDotRadius), + ll_round(pos_map.mV[VY] - mDotRadius), + dot_width, + dot_width); + + F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), + LLVector2(local_mouse_x,local_mouse_y)); + if(dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared) + { + mClosestAgentToCursor = gAgent.getID(); + } + } // Draw frustum F32 meters_to_pixels = mScale/ LLWorld::getInstance()->getRegionWidthInMeters(); @@ -399,7 +454,7 @@ void LLNetMap::draw() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if( mRotateMap ) + if( rotate_map ) { gGL.color4fv((map_frustum_color()).mV); @@ -416,7 +471,7 @@ void LLNetMap::draw() // If we don't rotate the map, we have to rotate the frustum. gGL.pushMatrix(); gGL.translatef( ctr_x, ctr_y, 0 ); - glRotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f); + gGL.rotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f); gGL.begin( LLRender::TRIANGLES ); gGL.vertex2f( 0, 0 ); gGL.vertex2f( -half_width_pixels, far_clip_pixels ); @@ -426,12 +481,23 @@ void LLNetMap::draw() } } + gGL.popMatrix(); + gGL.popUIMatrix(); + LLUICtrl::draw(); } -LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos ) +void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent) { - LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal(); + LLUICtrl::reshape(width, height, called_from_parent); + createObjectImage(); +} + +LLVector3 LLNetMap::globalPosToView(const LLVector3d& global_pos) +{ + LLVector3d camera_position = gAgentCamera.getCameraPositionGlobal(); + + LLVector3d relative_pos_global = global_pos - camera_position; LLVector3 pos_local; pos_local.setVec(relative_pos_global); // convert to floats from doubles @@ -439,15 +505,16 @@ LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos ) pos_local.mV[VY] *= mPixelsPerMeter; // leave Z component in meters - if( mRotateMap ) + static LLUICachedControl<bool> rotate_map("MiniMapRotate", true); + if( rotate_map ) { F32 radians = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); pos_local.rotVec( rot ); } - pos_local.mV[VX] += getRect().getWidth() / 2 + mCurPanX; - pos_local.mV[VY] += getRect().getHeight() / 2 + mCurPanY; + pos_local.mV[VX] += getRect().getWidth() / 2 + mCurPan.mV[VX]; + pos_local.mV[VY] += getRect().getHeight() / 2 + mCurPan.mV[VY]; return pos_local; } @@ -455,7 +522,7 @@ LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos ) void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, BOOL draw_arrow ) { - LLVector3 pos_local = globalPosToView( pos_global ); + LLVector3 pos_local = globalPosToView(pos_global); if( (pos_local.mV[VX] < 0) || (pos_local.mV[VY] < 0) || (pos_local.mV[VX] >= getRect().getWidth()) || @@ -463,8 +530,8 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, { if (draw_arrow) { - S32 x = llround( pos_local.mV[VX] ); - S32 y = llround( pos_local.mV[VY] ); + S32 x = ll_round( pos_local.mV[VX] ); + S32 y = ll_round( pos_local.mV[VY] ); LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10 ); LLWorldMapView::drawTrackingArrow( getRect(), x, y, color ); } @@ -480,14 +547,15 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y ) { - x -= llround(getRect().getWidth() / 2 + mCurPanX); - y -= llround(getRect().getHeight() / 2 + mCurPanY); + x -= ll_round(getRect().getWidth() / 2 + mCurPan.mV[VX]); + y -= ll_round(getRect().getHeight() / 2 + mCurPan.mV[VY]); LLVector3 pos_local( (F32)x, (F32)y, 0 ); F32 radians = - atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); - if( mRotateMap ) + static LLUICachedControl<bool> rotate_map("MiniMapRotate", true); + if( rotate_map ) { LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); pos_local.rotVec( rot ); @@ -497,15 +565,29 @@ LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y ) LLVector3d pos_global; pos_global.setVec( pos_local ); - pos_global += gAgent.getCameraPositionGlobal(); + pos_global += gAgentCamera.getCameraPositionGlobal(); return pos_global; } BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks) { - // note that clicks are reversed from what you'd think - setScale(llclamp(mScale - clicks*MAP_SCALE_INCREMENT, MAP_SCALE_MIN, MAP_SCALE_MAX)); + // note that clicks are reversed from what you'd think: i.e. > 0 means zoom out, < 0 means zoom in + F32 new_scale = mScale * pow(MAP_SCALE_ZOOM_FACTOR, -clicks); + F32 old_scale = mScale; + + setScale(new_scale); + + static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true); + if (!auto_center) + { + // Adjust pan to center the zoom on the mouse pointer + LLVector2 zoom_offset; + zoom_offset.mV[VX] = x - getRect().getWidth() / 2; + zoom_offset.mV[VY] = y - getRect().getHeight() / 2; + mCurPan -= zoom_offset * mScale / old_scale - zoom_offset; + } + return TRUE; } @@ -515,45 +597,36 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) { return FALSE; } - - // mToolTipMsg = "[AGENT][REGION](Double-click to open Map)" - - LLStringUtil::format_map_t args; - std::string fullname; - if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, fullname)) - { - args["[AGENT]"] = fullname + "\n"; - } - else - { - args["[AGENT]"] = ""; - } - - LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); - if( region ) - { - args["[REGION]"] = region->getName() + "\n"; - } - else + + // If the cursor is near an avatar on the minimap, a mini-inspector will be + // shown for the avatar, instead of the normal map tooltip. + if (handleToolTipAgent(mClosestAgentToCursor)) { - args["[REGION]"] = ""; + return TRUE; } - - std::string msg = mToolTipMsg; - LLStringUtil::format(msg, args); - + LLRect sticky_rect; - // set sticky_rect - if (region) + std::string region_name; + LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); + if(region) { + // set sticky_rect S32 SLOP = 4; - localPointToScreen( - x - SLOP, y - SLOP, - &(sticky_rect.mLeft), &(sticky_rect.mBottom) ); + localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect.mLeft), &(sticky_rect.mBottom)); sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP; sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP; + + region_name = region->getName(); + if (!region_name.empty()) + { + region_name += "\n"; + } } + LLStringUtil::format_map_t args; + args["[REGION]"] = region_name; + std::string msg = mToolTipMsg; + LLStringUtil::format(msg, args); LLToolTipMgr::instance().show(LLToolTip::Params() .message(msg) .sticky_rect(sticky_rect)); @@ -561,15 +634,57 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask ) return TRUE; } +BOOL LLNetMap::handleToolTipAgent(const LLUUID& avatar_id) +{ + LLAvatarName av_name; + if (avatar_id.isNull() || !LLAvatarNameCache::get(avatar_id, &av_name)) + { + return FALSE; + } + + // only show tooltip if same inspector not already open + LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar"); + if (!existing_inspector + || !existing_inspector->getVisible() + || existing_inspector->getKey()["avatar_id"].asUUID() != avatar_id) + { + LLInspector::Params p; + p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>()); + p.message(av_name.getCompleteName()); + p.image.name("Inspector_I"); + p.click_callback(boost::bind(showAvatarInspector, avatar_id)); + p.visible_time_near(6.f); + p.visible_time_far(3.f); + p.delay_time(0.35f); + p.wrap(false); + + LLToolTipMgr::instance().show(p); + } + return TRUE; +} + +// static +void LLNetMap::showAvatarInspector(const LLUUID& avatar_id) +{ + LLSD params; + params["avatar_id"] = avatar_id; + + if (LLToolTipMgr::instance().toolTipVisible()) + { + LLRect rect = LLToolTipMgr::instance().getToolTipRect(); + params["pos"]["x"] = rect.mLeft; + params["pos"]["y"] = rect.mTop; + } + + LLFloaterReg::showInstance("inspect_avatar", params); +} void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters ) { LLVector3 local_pos; local_pos.setVec( pos - mObjectImageCenterGlobal ); - F32 radius_clamped = llmin(radius_meters, MAX_PRIM_RADIUS); - - S32 diameter_pixels = llround(2 * radius_clamped * mObjectMapTPM); + S32 diameter_pixels = ll_round(2 * radius_meters * mObjectMapTPM); renderPoint( local_pos, color, diameter_pixels ); } @@ -585,8 +700,8 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, const S32 image_width = (S32)mObjectImagep->getWidth(); const S32 image_height = (S32)mObjectImagep->getHeight(); - S32 x_offset = llround(pos_local.mV[VX] * mObjectMapTPM + image_width / 2); - S32 y_offset = llround(pos_local.mV[VY] * mObjectMapTPM + image_height / 2); + S32 x_offset = ll_round(pos_local.mV[VX] * mObjectMapTPM + image_width / 2); + S32 y_offset = ll_round(pos_local.mV[VY] * mObjectMapTPM + image_height / 2); if ((x_offset < 0) || (x_offset >= image_width)) { @@ -662,13 +777,13 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, void LLNetMap::createObjectImage() { // Find the size of the side of a square that surrounds the circle that surrounds getRect(). - F32 half_width = (F32)(getRect().getWidth() / 2); - F32 half_height = (F32)(getRect().getHeight() / 2); - F32 radius = sqrt( half_width * half_width + half_height * half_height ); - S32 square_size = S32( 2 * radius ); + // ... which is, the diagonal of the rect. + F32 width = (F32)getRect().getWidth(); + F32 height = (F32)getRect().getHeight(); + S32 square_size = ll_round( sqrt(width*width + height*height) ); // Find the least power of two >= the minimum size. - const S32 MIN_SIZE = 32; + const S32 MIN_SIZE = 64; const S32 MAX_SIZE = 256; S32 img_size = MIN_SIZE; while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) ) @@ -684,7 +799,193 @@ void LLNetMap::createObjectImage() U8* data = mObjectRawImagep->getData(); memset( data, 0, img_size * img_size * 4 ); mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE); - setScale(mScale); } - mUpdateNow = TRUE; + setScale(mScale); + mUpdateNow = true; +} + +BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + if (!(mask & MASK_SHIFT)) return FALSE; + + // Start panning + gFocusMgr.setMouseCapture(this); + + mStartPan = mCurPan; + mMouseDown.mX = x; + mMouseDown.mY = y; + return TRUE; +} + +BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) +{ + if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3) + handleClick(x,y,mask); + + if (hasMouseCapture()) + { + if (mPanning) + { + // restore mouse cursor + S32 local_x, local_y; + local_x = mMouseDown.mX + llfloor(mCurPan.mV[VX] - mStartPan.mV[VX]); + local_y = mMouseDown.mY + llfloor(mCurPan.mV[VY] - mStartPan.mV[VY]); + LLRect clip_rect = getRect(); + clip_rect.stretch(-8); + clip_rect.clipPointToRect(mMouseDown.mX, mMouseDown.mY, local_x, local_y); + LLUI::setMousePositionLocal(this, local_x, local_y); + + // finish the pan + mPanning = false; + + mMouseDown.set(0, 0); + + // auto centre + mTargetPan.setZero(); + } + gViewerWindow->showCursor(); + gFocusMgr.setMouseCapture(NULL); + return TRUE; + } + return FALSE; +} + +BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPopupMenu) + { + mPopupMenu->buildDrawLabels(); + mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + mPopupMenu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0)); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + } + return TRUE; +} + +BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask) +{ + // TODO: allow clicking an avatar on minimap to select avatar in the nearby avatar list + // if(mClosestAgentToCursor.notNull()) + // mNearbyList->selectUser(mClosestAgentToCursor); + // Needs a registered observer i guess to accomplish this without using + // globals to tell the mNearbyList in llpeoplepanel to select the user + return TRUE; +} + +BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + LLVector3d pos_global = viewPosToGlobal(x, y); + + bool double_click_teleport = gSavedSettings.getBOOL("DoubleClickTeleport"); + bool double_click_show_world_map = gSavedSettings.getBOOL("DoubleClickShowWorldMap"); + + if (double_click_teleport || double_click_show_world_map) + { + // If we're not tracking a beacon already, double-click will set one + if (!LLTracker::isTracking(NULL)) + { + LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance(); + if (world_map) + { + world_map->trackLocation(pos_global); + } + } + } + + if (double_click_teleport) + { + // If DoubleClickTeleport is on, double clicking the minimap will teleport there + gAgent.teleportViaLocationLookAt(pos_global); + } + else if (double_click_show_world_map) + { + LLFloaterReg::showInstance("world_map"); + } + return TRUE; +} + +// static +bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop ) +{ + S32 dx = x - start_x; + S32 dy = y - start_y; + + return (dx <= -slop || slop <= dx || dy <= -slop || slop <= dy); +} + +BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask ) +{ + if (hasMouseCapture()) + { + if (mPanning || outsideSlop(x, y, mMouseDown.mX, mMouseDown.mY, MOUSE_DRAG_SLOP)) + { + if (!mPanning) + { + // just started panning, so hide cursor + mPanning = true; + gViewerWindow->hideCursor(); + } + + LLVector2 delta(static_cast<F32>(gViewerWindow->getCurrentMouseDX()), + static_cast<F32>(gViewerWindow->getCurrentMouseDY())); + + // Set pan to value at start of drag + offset + mCurPan += delta; + mTargetPan = mCurPan; + + gViewerWindow->moveCursorToCenter(); + } + + // Doesn't really matter, cursor should be hidden + gViewerWindow->setCursor( UI_CURSOR_TOOLPAN ); + } + else + { + if (mask & MASK_SHIFT) + { + // If shift is held, change the cursor to hint that the map can be dragged + gViewerWindow->setCursor( UI_CURSOR_TOOLPAN ); + } + else + { + gViewerWindow->setCursor( UI_CURSOR_CROSS ); + } + } + + return TRUE; +} + +void LLNetMap::handleZoom(const LLSD& userdata) +{ + std::string level = userdata.asString(); + + F32 scale = 0.0f; + if (level == std::string("default")) + { + LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale"); + if(pvar) + { + pvar->resetToDefault(); + scale = gSavedSettings.getF32("MiniMapScale"); + } + } + else if (level == std::string("close")) + scale = LLNetMap::MAP_SCALE_MAX; + else if (level == std::string("medium")) + scale = LLNetMap::MAP_SCALE_MID; + else if (level == std::string("far")) + scale = LLNetMap::MAP_SCALE_MIN; + if (scale != 0.0f) + { + setScale(scale); + } +} + +void LLNetMap::handleStopTracking (const LLSD& userdata) +{ + if (mPopupMenu) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL)); + } } |