llnetmap.cpp

Go to the documentation of this file.
00001 
00033 #include "llviewerprecompiledheaders.h"
00034 
00035 #include "llnetmap.h"
00036 
00037 #include "indra_constants.h"
00038 #include "llui.h"
00039 #include "llmath.h"             // clampf()
00040 #include "llfocusmgr.h"
00041 #include "llglimmediate.h"
00042 
00043 #include "llagent.h"
00044 #include "llcallingcard.h"
00045 #include "llcolorscheme.h"
00046 #include "llviewercontrol.h"
00047 #include "llfloaterworldmap.h"
00048 #include "llfloatermap.h"
00049 #include "llframetimer.h"
00050 #include "lltracker.h"
00051 #include "llmenugl.h"
00052 #include "llstatgraph.h"
00053 #include "llsurface.h"
00054 #include "lltextbox.h"
00055 #include "lluuid.h"
00056 #include "llviewercamera.h"
00057 #include "llviewerimage.h"
00058 #include "llviewerimagelist.h"
00059 #include "llviewermenu.h"
00060 #include "llviewerobjectlist.h"
00061 #include "llviewermenu.h"
00062 #include "llviewerparceloverlay.h"
00063 #include "llviewerregion.h"
00064 #include "llviewerwindow.h"
00065 #include "llvoavatar.h"
00066 #include "llworld.h"
00067 #include "llworldmapview.h"             // shared draw code
00068 #include "llappviewer.h"                                // Only for constants!
00069 
00070 #include "llglheaders.h"
00071 
00072 const F32 MAP_SCALE_MIN = 64;
00073 const F32 MAP_SCALE_MID = 172;
00074 const F32 MAP_SCALE_MAX = 512;
00075 const F32 MAP_SCALE_INCREMENT = 16;
00076 
00077 const S32 TRACKING_RADIUS = 3;
00078 
00079 //static
00080 BOOL LLNetMap::sRotateMap = FALSE;
00081 LLNetMap* LLNetMap::sInstance = NULL;
00082 
00083 LLNetMap::LLNetMap(
00084         const std::string& name,
00085         const LLRect& rect,
00086         const LLColor4& bg_color )
00087         :
00088         LLUICtrl(name, rect, FALSE, NULL, NULL), mBackgroundColor( bg_color ),
00089         mObjectMapTPM(1.f),
00090         mObjectMapPixels(255.f),
00091         mTargetPanX( 0.f ),
00092         mTargetPanY( 0.f ),
00093         mCurPanX( 0.f ),
00094         mCurPanY( 0.f ),
00095         mUpdateNow( FALSE )
00096 {
00097         mPixelsPerMeter = gMiniMapScale / REGION_WIDTH_METERS;
00098 
00099         LLNetMap::sRotateMap = gSavedSettings.getBOOL( "MiniMapRotate" );
00100         
00101         // Surface texture is dynamically generated/updated.
00102 //      createObjectImage();
00103 
00104         mObjectImageCenterGlobal = gAgent.getCameraPositionGlobal();
00105         
00106         // TODO: exteralize hardcoded constants.
00107         const S32 DIR_WIDTH = 10;
00108         const S32 DIR_HEIGHT = 10;
00109         LLRect major_dir_rect(  0, DIR_HEIGHT, DIR_WIDTH, 0 );
00110         const LLColor4 minor_color( 1.f, 1.f, 1.f, .7f );
00111         const LLRect minor_dir_rect(  0, DIR_HEIGHT, DIR_WIDTH * 2, 0 );
00112 
00113         // Note: removing special treatment for north compass point (DEV-10559). -MG
00114         //mTextBoxNorth = new LLTextBox( "N", major_dir_rect );
00115         //mTextBoxNorth->setFontStyle(LLFontGL::DROP_SHADOW_SOFT);
00116         //addChild( mTextBoxNorth );
00117         mTextBoxNorth = new LLTextBox( "N", major_dir_rect );
00118         mTextBoxNorth->setColor( minor_color );
00119         addChild( mTextBoxNorth );
00120         
00121         mTextBoxEast =  new LLTextBox( "E", major_dir_rect );
00122         mTextBoxEast->setColor( minor_color );
00123         addChild( mTextBoxEast );
00124         
00125         major_dir_rect.mRight += 1 ;
00126         mTextBoxWest =  new LLTextBox( "W", major_dir_rect );
00127         mTextBoxWest->setColor( minor_color );
00128         addChild( mTextBoxWest );
00129         major_dir_rect.mRight -= 1 ;
00130 
00131         mTextBoxSouth = new LLTextBox( "S", major_dir_rect );
00132         mTextBoxSouth->setColor( minor_color );
00133         addChild( mTextBoxSouth );
00134 
00135         mTextBoxSouthEast =     new LLTextBox( "SE", minor_dir_rect );
00136         mTextBoxSouthEast->setColor( minor_color );
00137         addChild( mTextBoxSouthEast );
00138         
00139         mTextBoxNorthEast = new LLTextBox( "NE", minor_dir_rect );
00140         mTextBoxNorthEast->setColor( minor_color );
00141         addChild( mTextBoxNorthEast );
00142         
00143         mTextBoxSouthWest =     new LLTextBox( "SW", minor_dir_rect );
00144         mTextBoxSouthWest->setColor( minor_color );
00145         addChild( mTextBoxSouthWest );
00146 
00147         mTextBoxNorthWest = new LLTextBox( "NW", minor_dir_rect );
00148         mTextBoxNorthWest->setColor( minor_color );
00149         addChild( mTextBoxNorthWest );
00150 
00151         // Right-click menu
00152         LLMenuGL* menu;
00153         menu = new LLMenuGL("popup");
00154         menu->setCanTearOff(FALSE);
00155         menu->append(new LLMenuItemCallGL("Zoom Close", handleZoomLevel,
00156                                                                                 NULL, (void*)2) );
00157         menu->append(new LLMenuItemCallGL("Zoom Medium", handleZoomLevel,
00158                                                                                 NULL, (void*)1) );
00159         menu->append(new LLMenuItemCallGL("Zoom Far", handleZoomLevel,
00160                                                                                 NULL, (void*)0) );
00161         menu->appendSeparator();
00162         menu->append(new LLMenuItemCallGL("Stop Tracking", &LLTracker::stopTracking,
00163                                                                                 &LLTracker::isTracking, NULL) );
00164         menu->setVisible(FALSE);
00165         addChild(menu);
00166         mPopupMenuHandle = menu->getHandle();
00167 
00168         sInstance = this;
00169 }
00170 
00171 LLNetMap::~LLNetMap()
00172 {
00173         sInstance = NULL;
00174 }
00175 
00176 void LLNetMap::setScale( F32 scale )
00177 {
00178         gMiniMapScale = scale;
00179         if (gMiniMapScale == 0.f)
00180         {
00181                 gMiniMapScale = 0.1f;
00182         }
00183 
00184         if (mObjectImagep.notNull())
00185         {
00186                 F32 half_width = (F32)(getRect().getWidth() / 2);
00187                 F32 half_height = (F32)(getRect().getHeight() / 2);
00188                 F32 radius = sqrt( half_width * half_width + half_height * half_height );
00189                 F32 region_widths = (2.f*radius)/gMiniMapScale;
00190                 F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters();
00191                 F32 num_pixels = (F32)mObjectImagep->getWidth();
00192                 mObjectMapTPM = num_pixels/meters;
00193                 mObjectMapPixels = 2.f*radius;
00194         }
00195 
00196         mPixelsPerMeter = gMiniMapScale / REGION_WIDTH_METERS;
00197 
00198         mUpdateNow = TRUE;
00199 }
00200 
00201 void LLNetMap::translatePan( F32 delta_x, F32 delta_y )
00202 {
00203         mTargetPanX += delta_x;
00204         mTargetPanY += delta_y;
00205 }
00206 
00207 
00209 
00210 void LLNetMap::draw()
00211 {
00212         static LLFrameTimer map_timer;
00213 
00214         if (mObjectImagep.isNull())
00215         {
00216                 createObjectImage();
00217         }
00218         
00219         mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
00220         mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
00221 
00222         // Prepare a scissor region
00223         F32 rotation = 0;
00224 
00225         {
00226                 LLGLEnable scissor(GL_SCISSOR_TEST);
00227                 
00228                 {
00229                         LLGLSNoTexture no_texture;
00230                         LLLocalClipRect clip(getLocalRect());
00231 
00232                         glMatrixMode(GL_MODELVIEW);
00233 
00234                         // Draw background rectangle
00235                         gGL.color4fv( mBackgroundColor.mV );
00236                         gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0);
00237                 }
00238 
00239                 // region 0,0 is in the middle
00240                 S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPanX);
00241                 S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPanY);
00242 
00243                 gGL.pushMatrix();
00244 
00245                 gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f);
00246 
00247                 if( LLNetMap::sRotateMap )
00248                 {
00249                         // rotate subsequent draws to agent rotation
00250                         rotation = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] );
00251                         glRotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f);
00252                 }
00253 
00254                 // figure out where agent is
00255                 S32 region_width = llround(LLWorld::getInstance()->getRegionWidthInMeters());
00256 
00257                 for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->mActiveRegionList.begin();
00258                          iter != LLWorld::getInstance()->mActiveRegionList.end(); ++iter)
00259                 {
00260                         LLViewerRegion* regionp = *iter;
00261                         // Find x and y position relative to camera's center.
00262                         LLVector3 origin_agent = regionp->getOriginAgent();
00263                         LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent();
00264                         F32 relative_x = (rel_region_pos.mV[0] / region_width) * gMiniMapScale;
00265                         F32 relative_y = (rel_region_pos.mV[1] / region_width) * gMiniMapScale;
00266 
00267                         // background region rectangle
00268                         F32 bottom =    relative_y;
00269                         F32 left =              relative_x;
00270                         F32 top =               bottom + gMiniMapScale ;
00271                         F32 right =             left + gMiniMapScale ;
00272 
00273                         if (regionp == gAgent.getRegion())
00274                         {
00275                                 gGL.color4f(1.f, 1.f, 1.f, 1.f);
00276                         }
00277                         else
00278                         {
00279                                 gGL.color4f(0.8f, 0.8f, 0.8f, 1.f);
00280                         }
00281 
00282                         if (!regionp->mAlive)
00283                         {
00284                                 gGL.color4f(1.f, 0.5f, 0.5f, 1.f);
00285                         }
00286 
00287 
00288                         // Draw using texture.
00289                         LLViewerImage::bindTexture(regionp->getLand().getSTexture());
00290                         gGL.begin(LLVertexBuffer::QUADS);
00291                                 gGL.texCoord2f(0.f, 1.f);
00292                                 gGL.vertex2f(left, top);
00293                                 gGL.texCoord2f(0.f, 0.f);
00294                                 gGL.vertex2f(left, bottom);
00295                                 gGL.texCoord2f(1.f, 0.f);
00296                                 gGL.vertex2f(right, bottom);
00297                                 gGL.texCoord2f(1.f, 1.f);
00298                                 gGL.vertex2f(right, top);
00299                         gGL.end();
00300 
00301                         // Draw water
00302                         glAlphaFunc(GL_GREATER, ABOVE_WATERLINE_ALPHA / 255.f );
00303                         {
00304                                 if (regionp->getLand().getWaterTexture())
00305                                 {
00306                                         LLViewerImage::bindTexture(regionp->getLand().getWaterTexture());
00307                                         gGL.begin(LLVertexBuffer::QUADS);
00308                                                 gGL.texCoord2f(0.f, 1.f);
00309                                                 gGL.vertex2f(left, top);
00310                                                 gGL.texCoord2f(0.f, 0.f);
00311                                                 gGL.vertex2f(left, bottom);
00312                                                 gGL.texCoord2f(1.f, 0.f);
00313                                                 gGL.vertex2f(right, bottom);
00314                                                 gGL.texCoord2f(1.f, 1.f);
00315                                                 gGL.vertex2f(right, top);
00316                                         gGL.end();
00317                                 }
00318                         }
00319                         glAlphaFunc(GL_GREATER,0.01f);
00320                 }
00321                 
00322 
00323                 LLVector3d old_center = mObjectImageCenterGlobal;
00324                 LLVector3d new_center = gAgent.getCameraPositionGlobal();
00325 
00326                 new_center.mdV[0] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[0]);
00327                 new_center.mdV[1] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[1]);
00328                 new_center.mdV[2] = 0.f;
00329 
00330                 if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f))
00331                 {
00332                         mUpdateNow = FALSE;
00333                         mObjectImageCenterGlobal = new_center;
00334 
00335                         // Center moved enough.
00336                         // Create the base texture.
00337                         U8 *default_texture = mObjectRawImagep->getData();
00338                         memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() );
00339 
00340                         // Draw buildings
00341                         gObjectList.renderObjectsForMap(*this);
00342 
00343                         mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight());
00344                         
00345                         map_timer.reset();
00346                 }
00347 
00348                 LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal);
00349                 map_center_agent -= gAgent.getCameraPositionAgent();
00350                 map_center_agent.mV[VX] *= gMiniMapScale/region_width;
00351                 map_center_agent.mV[VY] *= gMiniMapScale/region_width;
00352 
00353                 LLViewerImage::bindTexture(mObjectImagep);
00354                 F32 image_half_width = 0.5f*mObjectMapPixels;
00355                 F32 image_half_height = 0.5f*mObjectMapPixels;
00356 
00357                 gGL.begin(LLVertexBuffer::QUADS);
00358                         gGL.texCoord2f(0.f, 1.f);
00359                         gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]);
00360                         gGL.texCoord2f(0.f, 0.f);
00361                         gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height);
00362                         gGL.texCoord2f(1.f, 0.f);
00363                         gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height);
00364                         gGL.texCoord2f(1.f, 1.f);
00365                         gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
00366                 gGL.end();
00367 
00368                 gGL.popMatrix();
00369 
00370                 LLVector3d pos_global;
00371                 LLVector3 pos_map;
00372 
00373                 // Draw avatars
00374                 for (LLWorld::region_list_t::iterator iter = LLWorld::getInstance()->mActiveRegionList.begin();
00375                          iter != LLWorld::getInstance()->mActiveRegionList.end(); ++iter)
00376                 {
00377                         LLViewerRegion* regionp = *iter;
00378                         const LLVector3d& origin_global = regionp->getOriginGlobal();
00379 
00380                         S32 count = regionp->mMapAvatars.count();
00381                         S32 i;
00382                         LLVector3 pos_local;
00383                         U32 compact_local;
00384                         U8 bits;
00385                         // TODO: it'd be very cool to draw these in sorted order from lowest Z to highest.
00386                         // just be careful to sort the avatar IDs along with the positions. -MG
00387                         for (i = 0; i < count; i++)
00388                         {
00389                                 compact_local = regionp->mMapAvatars.get(i);
00390 
00391                                 bits = compact_local & 0xFF;
00392                                 pos_local.mV[VZ] = F32(bits) * 4.f;
00393                                 compact_local >>= 8;
00394 
00395                                 bits = compact_local & 0xFF;
00396                                 pos_local.mV[VY] = (F32)bits;
00397                                 compact_local >>= 8;
00398 
00399                                 bits = compact_local & 0xFF;
00400                                 pos_local.mV[VX] = (F32)bits;
00401 
00402                                 pos_global.setVec( pos_local );
00403                                 pos_global += origin_global;
00404 
00405                                 pos_map = globalPosToView(pos_global);
00406 
00407                                 BOOL show_as_friend = FALSE;
00408                                 if( i < regionp->mMapAvatarIDs.count())
00409                                 {
00410                                         show_as_friend = is_agent_friend(regionp->mMapAvatarIDs.get(i));
00411                                 }
00412                                 LLWorldMapView::drawAvatar(
00413                                         pos_map.mV[VX], pos_map.mV[VY], 
00414                                         show_as_friend ? gFriendMapColor : gAvatarMapColor, 
00415                                         pos_map.mV[VZ]);
00416                         }
00417                 }
00418 
00419                 // Draw dot for autopilot target
00420                 if (gAgent.getAutoPilot())
00421                 {
00422                         drawTracking( gAgent.getAutoPilotTargetGlobal(), gTrackColor );
00423                 }
00424                 else
00425                 {
00426                         LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
00427                         if (  LLTracker::TRACKING_AVATAR == tracking_status )
00428                         {
00429                                 drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor );
00430                         } 
00431                         else if ( LLTracker::TRACKING_LANDMARK == tracking_status 
00432                                         || LLTracker::TRACKING_LOCATION == tracking_status )
00433                         {
00434                                 drawTracking( LLTracker::getTrackedPositionGlobal(), gTrackColor );
00435                         }
00436                 }
00437 
00438                 // Draw dot for self avatar position
00439                 pos_global = gAgent.getPositionGlobal();
00440                 pos_map = globalPosToView(pos_global);
00441                 LLUIImagePtr you = LLWorldMapView::sAvatarYouSmallImage;
00442                 you->draw(
00443                         llround(pos_map.mV[VX]) - you->getWidth()/2, 
00444                         llround(pos_map.mV[VY]) - you->getHeight()/2);
00445 
00446                 // Draw frustum
00447                 F32 meters_to_pixels = gMiniMapScale/ LLWorld::getInstance()->getRegionWidthInMeters();
00448 
00449                 F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
00450                 F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
00451                 F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
00452 
00453                 F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
00454                 F32 half_width_pixels = half_width_meters * meters_to_pixels;
00455                 
00456                 F32 ctr_x = (F32)center_sw_left;
00457                 F32 ctr_y = (F32)center_sw_bottom;
00458 
00459 
00460                 LLGLSNoTexture no_texture;
00461 
00462                 if( LLNetMap::sRotateMap )
00463                 {
00464                         gGL.color4fv(gFrustumMapColor.mV);
00465 
00466                         gGL.begin( LLVertexBuffer::TRIANGLES  );
00467                                 gGL.vertex2f( ctr_x, ctr_y );
00468                                 gGL.vertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
00469                                 gGL.vertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
00470                         gGL.end();
00471                 }
00472                 else
00473                 {
00474                         gGL.color4fv(gRotatingFrustumMapColor.mV);
00475                         
00476                         // If we don't rotate the map, we have to rotate the frustum.
00477                         gGL.pushMatrix();
00478                                 gGL.translatef( ctr_x, ctr_y, 0 );
00479                                 glRotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
00480                                 gGL.begin( LLVertexBuffer::TRIANGLES  );
00481                                         gGL.vertex2f( 0, 0 );
00482                                         gGL.vertex2f( -half_width_pixels, far_clip_pixels );
00483                                         gGL.vertex2f(  half_width_pixels, far_clip_pixels );
00484                                 gGL.end();
00485                         gGL.popMatrix();
00486                 }
00487         }
00488         
00489         // Rotation of 0 means that North is up
00490         setDirectionPos( mTextBoxEast,  rotation );
00491         setDirectionPos( mTextBoxNorth, rotation + F_PI_BY_TWO );
00492         setDirectionPos( mTextBoxWest,  rotation + F_PI );
00493         setDirectionPos( mTextBoxSouth, rotation + F_PI + F_PI_BY_TWO );
00494 
00495         setDirectionPos( mTextBoxNorthEast, rotation +                                          F_PI_BY_TWO / 2);
00496         setDirectionPos( mTextBoxNorthWest, rotation + F_PI_BY_TWO +            F_PI_BY_TWO / 2);
00497         setDirectionPos( mTextBoxSouthWest, rotation + F_PI +                           F_PI_BY_TWO / 2);
00498         setDirectionPos( mTextBoxSouthEast, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2);
00499 
00500         LLUICtrl::draw();
00501 }
00502 
00503 LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos )
00504 {
00505         LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal();
00506         LLVector3 pos_local;
00507         pos_local.setVec(relative_pos_global);  // convert to floats from doubles
00508 
00509         pos_local.mV[VX] *= mPixelsPerMeter;
00510         pos_local.mV[VY] *= mPixelsPerMeter;
00511         // leave Z component in meters
00512 
00513         if( LLNetMap::sRotateMap )
00514         {
00515                 F32 radians = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] );
00516                 LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f));
00517                 pos_local.rotVec( rot );
00518         }
00519 
00520         pos_local.mV[VX] += getRect().getWidth() / 2 + mCurPanX;
00521         pos_local.mV[VY] += getRect().getHeight() / 2 + mCurPanY;
00522 
00523         return pos_local;
00524 }
00525 
00526 void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, 
00527                                                         BOOL draw_arrow )
00528 {
00529         LLVector3 pos_local = globalPosToView( pos_global );
00530         if( (pos_local.mV[VX] < 0) ||
00531                 (pos_local.mV[VY] < 0) ||
00532                 (pos_local.mV[VX] >= getRect().getWidth()) ||
00533                 (pos_local.mV[VY] >= getRect().getHeight()) )
00534         {
00535                 if (draw_arrow)
00536                 {
00537                         S32 x = llround( pos_local.mV[VX] );
00538                         S32 y = llround( pos_local.mV[VY] );
00539                         LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10 );
00540                         LLWorldMapView::drawTrackingArrow( getRect(), x, y, color );
00541                 }
00542         }
00543         else
00544         {
00545                 LLWorldMapView::drawTrackingDot(pos_local.mV[VX], 
00546                                                                                 pos_local.mV[VY], 
00547                                                                                 color,
00548                                                                                 pos_local.mV[VZ]);
00549         }
00550 }
00551 
00552 LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
00553 {
00554         x -= llround(getRect().getWidth() / 2 + mCurPanX);
00555         y -= llround(getRect().getHeight() / 2 + mCurPanY);
00556 
00557         LLVector3 pos_local( (F32)x, (F32)y, 0 );
00558 
00559         F32 radians = - atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] );
00560 
00561         if( LLNetMap::sRotateMap )
00562         {
00563                 LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f));
00564                 pos_local.rotVec( rot );
00565         }
00566 
00567         pos_local *= ( LLWorld::getInstance()->getRegionWidthInMeters() / gMiniMapScale );
00568         
00569         LLVector3d pos_global;
00570         pos_global.setVec( pos_local );
00571         pos_global += gAgent.getCameraPositionGlobal();
00572 
00573         return pos_global;
00574 }
00575 
00576 BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
00577 {
00578         // note that clicks are reversed from what you'd think
00579         setScale(llclamp(gMiniMapScale - clicks*MAP_SCALE_INCREMENT, MAP_SCALE_MIN, MAP_SCALE_MAX));
00580         return TRUE;
00581 }
00582 
00583 BOOL LLNetMap::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen )
00584 {
00585         BOOL handled = FALSE;
00586         if (gDisconnected)
00587         {
00588                 return FALSE;
00589         }
00590         LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
00591         if( region )
00592         {
00593                 msg.assign( region->getName() );
00594 
00595 #ifndef LL_RELEASE_FOR_DOWNLOAD
00596                 char buffer[MAX_STRING];                /*Flawfinder: ignore*/
00597                 msg.append("\n");
00598                 region->getHost().getHostName(buffer, MAX_STRING);
00599                 msg.append(buffer);
00600                 msg.append("\n");
00601                 region->getHost().getString(buffer, MAX_STRING);
00602                 msg.append(buffer);
00603 #endif
00604                 // *TODO: put this under the control of XUI so it can be
00605                 // translated.
00606                 msg.append("\n(Double-click to open Map)");
00607 
00608                 S32 SLOP = 4;
00609                 localPointToScreen( 
00610                         x - SLOP, y - SLOP, 
00611                         &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
00612                 sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
00613                 sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
00614         }
00615         handled = TRUE;
00616         return handled;
00617 }
00618 
00619 
00620 void LLNetMap::setDirectionPos( LLTextBox* text_box, F32 rotation )
00621 {
00622         // Rotation is in radians.
00623         // Rotation of 0 means x = 1, y = 0 on the unit circle.
00624 
00625 
00626         F32 map_half_height = (F32)(getRect().getHeight() / 2);
00627         F32 map_half_width = (F32)(getRect().getWidth() / 2);
00628         F32 text_half_height = (F32)(text_box->getRect().getHeight() / 2);
00629         F32 text_half_width = (F32)(text_box->getRect().getWidth() / 2);
00630         F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width );
00631 
00632         // Inset by a little to account for position display.
00633         radius -= 8.f;
00634 
00635         text_box->setOrigin( 
00636                 llround(map_half_width - text_half_width + radius * cos( rotation )),
00637                 llround(map_half_height - text_half_height + radius * sin( rotation )) );
00638 }
00639 
00640 void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters )
00641 {
00642         LLVector3 local_pos;
00643         local_pos.setVec( pos - mObjectImageCenterGlobal );
00644 
00645         S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM);
00646         renderPoint( local_pos, color, diameter_pixels );
00647 }
00648 
00649 
00650 void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, 
00651                                                    S32 diameter, S32 relative_height)
00652 {
00653         if (diameter <= 0)
00654         {
00655                 return;
00656         }
00657 
00658         const S32 image_width = (S32)mObjectImagep->getWidth();
00659         const S32 image_height = (S32)mObjectImagep->getHeight();
00660 
00661         S32 x_offset = llround(pos_local.mV[VX] * mObjectMapTPM + image_width / 2);
00662         S32 y_offset = llround(pos_local.mV[VY] * mObjectMapTPM + image_height / 2);
00663 
00664         if ((x_offset < 0) || (x_offset >= image_width))
00665         {
00666                 return;
00667         }
00668         if ((y_offset < 0) || (y_offset >= image_height))
00669         {
00670                 return;
00671         }
00672 
00673         U8 *datap = mObjectRawImagep->getData();
00674 
00675         S32 neg_radius = diameter / 2;
00676         S32 pos_radius = diameter - neg_radius;
00677         S32 x, y;
00678 
00679         if (relative_height > 0)
00680         {
00681                 // ...point above agent
00682                 S32 px, py;
00683 
00684                 // vertical line
00685                 px = x_offset;
00686                 for (y = -neg_radius; y < pos_radius; y++)
00687                 {
00688                         py = y_offset + y;
00689                         if ((py < 0) || (py >= image_height))
00690                         {
00691                                 continue;
00692                         }
00693                         S32 offset = px + py * image_width;
00694                         ((U32*)datap)[offset] = color.mAll;
00695                 }
00696 
00697                 // top line
00698                 py = y_offset + pos_radius - 1;
00699                 for (x = -neg_radius; x < pos_radius; x++)
00700                 {
00701                         px = x_offset + x;
00702                         if ((px < 0) || (px >= image_width))
00703                         {
00704                                 continue;
00705                         }
00706                         S32 offset = px + py * image_width;
00707                         ((U32*)datap)[offset] = color.mAll;
00708                 }
00709         }
00710         else
00711         {
00712                 // ...point level with agent
00713                 for (x = -neg_radius; x < pos_radius; x++)
00714                 {
00715                         S32 p_x = x_offset + x;
00716                         if ((p_x < 0) || (p_x >= image_width))
00717                         {
00718                                 continue;
00719                         }
00720 
00721                         for (y = -neg_radius; y < pos_radius; y++)
00722                         {
00723                                 S32 p_y = y_offset + y;
00724                                 if ((p_y < 0) || (p_y >= image_height))
00725                                 {
00726                                         continue;
00727                                 }
00728                                 S32 offset = p_x + p_y * image_width;
00729                                 ((U32*)datap)[offset] = color.mAll;
00730                         }
00731                 }
00732         }
00733 }
00734 
00735 void LLNetMap::createObjectImage()
00736 {
00737         // Find the size of the side of a square that surrounds the circle that surrounds getRect().
00738         F32 half_width = (F32)(getRect().getWidth() / 2);
00739         F32 half_height = (F32)(getRect().getHeight() / 2);
00740         F32 radius = sqrt( half_width * half_width + half_height * half_height );
00741         S32 square_size = S32( 2 * radius );
00742 
00743         // Find the least power of two >= the minimum size.
00744         const S32 MIN_SIZE = 32;
00745         const S32 MAX_SIZE = 256;
00746         S32 img_size = MIN_SIZE;
00747         while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) )
00748         {
00749                 img_size <<= 1;
00750         }
00751 
00752         if( mObjectImagep.isNull() ||
00753                 (mObjectImagep->getWidth() != img_size) ||
00754                 (mObjectImagep->getHeight() != img_size) )
00755         {
00756                 mObjectRawImagep = new LLImageRaw(img_size, img_size, 4);
00757                 U8* data = mObjectRawImagep->getData();
00758                 memset( data, 0, img_size * img_size * 4 );
00759                 mObjectImagep = new LLImageGL( mObjectRawImagep, FALSE);
00760                 setScale(gMiniMapScale);
00761         }
00762         mUpdateNow = TRUE;
00763 }
00764 
00765 BOOL LLNetMap::handleDoubleClick( S32 x, S32 y, MASK mask )
00766 {
00767         LLFloaterWorldMap::show(NULL, FALSE);
00768         return TRUE;
00769 }
00770 
00771 BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
00772 {
00773         LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
00774         if (menu)
00775         {
00776                 menu->buildDrawLabels();
00777                 menu->updateParent(LLMenuGL::sMenuContainer);
00778                 LLMenuGL::showPopup(this, menu, x, y);
00779         }
00780         return TRUE;
00781 }
00782 
00783 
00784 // static
00785 void LLNetMap::handleZoomLevel(void* which)
00786 {
00787         intptr_t level = (intptr_t)which;
00788 
00789         switch(level)
00790         {
00791         case 0:
00792                 LLNetMap::sInstance->setScale(MAP_SCALE_MIN);
00793                 break;
00794         case 1:
00795                 LLNetMap::sInstance->setScale(MAP_SCALE_MID);
00796                 break;
00797         case 2:
00798                 LLNetMap::sInstance->setScale(MAP_SCALE_MAX);
00799                 break;
00800         default:
00801                 break;
00802         }
00803 }

Generated on Fri May 16 08:33:48 2008 for SecondLife by  doxygen 1.5.5