diff options
Diffstat (limited to 'indra/newview/llnetmap.cpp')
-rw-r--r-- | indra/newview/llnetmap.cpp | 806 |
1 files changed, 806 insertions, 0 deletions
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp new file mode 100644 index 0000000000..178d707bb0 --- /dev/null +++ b/indra/newview/llnetmap.cpp @@ -0,0 +1,806 @@ +/** + * @file llnetmap.cpp + * @author James Cook + * @brief Display of surrounding regions, objects, and agents. View contained by LLFloaterMap. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnetmap.h" + +#include "indra_constants.h" +#include "llui.h" +#include "linked_lists.h" +#include "llmath.h" // clampf() +#include "llfocusmgr.h" + +#include "llagent.h" +#include "llcallingcard.h" +#include "llcolorscheme.h" +#include "llviewercontrol.h" +#include "llfloaterworldmap.h" +#include "llfloatermap.h" +#include "llframetimer.h" +#include "lltracker.h" +#include "llmenugl.h" +#include "llstatgraph.h" +#include "llsurface.h" +#include "lltextbox.h" +#include "llviewercamera.h" +#include "llviewerimage.h" +#include "llviewerimagelist.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerparceloverlay.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llworld.h" +#include "llworldmapview.h" // shared draw code +#include "viewer.h" // Only for constants! + +#include "llglheaders.h" + +const F32 MAP_SCALE_MIN = 64; +const F32 MAP_SCALE_MID = 172; +const F32 MAP_SCALE_MAX = 512; +const F32 MAP_SCALE_INCREMENT = 16; + +const S32 TRACKING_RADIUS = 3; + +//static +BOOL LLNetMap::sRotateMap = FALSE; +LLNetMap* LLNetMap::sInstance = NULL; + +LLNetMap::LLNetMap( + const std::string& name, + const LLRect& rect, + const LLColor4& bg_color ) + : + LLUICtrl(name, rect, FALSE, NULL, NULL), mBackgroundColor( bg_color ), + mObjectMapTPM(1.f), + mObjectMapPixels(255.f), + mTargetPanX( 0.f ), + mTargetPanY( 0.f ), + mCurPanX( 0.f ), + mCurPanY( 0.f ), + mUpdateNow( FALSE ) +{ + mPixelsPerMeter = gMiniMapScale / REGION_WIDTH_METERS; + + LLNetMap::sRotateMap = gSavedSettings.getBOOL( "MiniMapRotate" ); + + // Surface texture is dynamically generated/updated. +// createObjectImage(); + + mObjectImageCenterGlobal = gAgent.getCameraPositionGlobal(); + + const S32 DIR_WIDTH = 10; + const S32 DIR_HEIGHT = 10; + LLRect major_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH, 0 ); + + mTextBoxNorth = new LLTextBox( "N", major_dir_rect ); + mTextBoxNorth->setDropshadowVisible( TRUE ); + addChild( mTextBoxNorth ); + + LLColor4 minor_color( 1.f, 1.f, 1.f, .7f ); + + mTextBoxEast = new LLTextBox( "E", major_dir_rect ); + mTextBoxEast->setColor( minor_color ); + addChild( mTextBoxEast ); + + mTextBoxWest = new LLTextBox( "W", major_dir_rect ); + mTextBoxWest->setColor( minor_color ); + addChild( mTextBoxWest ); + + mTextBoxSouth = new LLTextBox( "S", major_dir_rect ); + mTextBoxSouth->setColor( minor_color ); + addChild( mTextBoxSouth ); + + LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0 ); + + mTextBoxSouthEast = new LLTextBox( "SE", minor_dir_rect ); + mTextBoxSouthEast->setColor( minor_color ); + addChild( mTextBoxSouthEast ); + + mTextBoxNorthEast = new LLTextBox( "NE", minor_dir_rect ); + mTextBoxNorthEast->setColor( minor_color ); + addChild( mTextBoxNorthEast ); + + mTextBoxSouthWest = new LLTextBox( "SW", minor_dir_rect ); + mTextBoxSouthWest->setColor( minor_color ); + addChild( mTextBoxSouthWest ); + + mTextBoxNorthWest = new LLTextBox( "NW", minor_dir_rect ); + mTextBoxNorthWest->setColor( minor_color ); + addChild( mTextBoxNorthWest ); + + // Right-click menu + LLMenuGL* menu; + menu = new LLMenuGL("popup"); + menu->setCanTearOff(FALSE); + menu->append(new LLMenuItemCallGL("Zoom Close", handleZoomLevel, + NULL, (void*)2) ); + menu->append(new LLMenuItemCallGL("Zoom Medium", handleZoomLevel, + NULL, (void*)1) ); + menu->append(new LLMenuItemCallGL("Zoom Far", handleZoomLevel, + NULL, (void*)0) ); + menu->appendSeparator(); + menu->append(new LLMenuItemCallGL("Stop Tracking", &LLTracker::stopTracking, + &LLTracker::isTracking, NULL) ); + menu->setVisible(FALSE); + addChild(menu); + mPopupMenuHandle = menu->mViewHandle; + + sInstance = this; + + gSavedSettings.getControl("MiniMapRotate")->addListener(&mNetMapListener); +} + +LLNetMap::~LLNetMap() +{ + sInstance = NULL; +} + +EWidgetType LLNetMap::getWidgetType() const +{ + return WIDGET_TYPE_NET_MAP; +} + +LLString LLNetMap::getWidgetTag() const +{ + return LL_NET_MAP_TAG; +} + + +void LLNetMap::setScale( F32 scale ) +{ + gMiniMapScale = scale; + if (gMiniMapScale == 0.f) + { + gMiniMapScale = 0.1f; + } + + if (mObjectImagep.notNull()) + { + F32 half_width = (F32)(mRect.getWidth() / 2); + F32 half_height = (F32)(mRect.getHeight() / 2); + F32 radius = sqrt( half_width * half_width + half_height * half_height ); + + F32 region_widths = (2.f*radius)/gMiniMapScale; + + F32 meters; + if (!gWorldPointer) + { + // Hack! Sometimes world hasn't been initialized at this point. + meters = 256.f*region_widths; + } + else + { + meters = region_widths * gWorldPointer->getRegionWidthInMeters(); + } + + F32 num_pixels = (F32)mObjectImagep->getWidth(); + mObjectMapTPM = num_pixels/meters; + mObjectMapPixels = 2.f*radius; + } + + mPixelsPerMeter = gMiniMapScale / REGION_WIDTH_METERS; + + mUpdateNow = TRUE; +} + +void LLNetMap::translatePan( F32 delta_x, F32 delta_y ) +{ + mTargetPanX += delta_x; + mTargetPanY += delta_y; +} + + +/////////////////////////////////////////////////////////////////////////////////// + +void LLNetMap::draw() +{ + static LLFrameTimer map_timer; + + if (!getVisible() || !gWorldPointer) + { + return; + } + if (mObjectImagep.isNull()) + { + createObjectImage(); + } + + mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); + mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); + + // Prepare a scissor region + // GLint params[4]; + // glGetIntegerv( GL_SCISSOR_BOX, params ); + F32 rotation = 0; + + { + LLGLEnable scissor(GL_SCISSOR_TEST); + + { + LLGLSNoTexture no_texture; + LLUI::setScissorRegionLocal(LLRect(0, mRect.getHeight(), mRect.getWidth(), 0)); + + glMatrixMode(GL_MODELVIEW); + + // Draw background rectangle + glColor4fv( mBackgroundColor.mV ); + gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0); + } + + // region 0,0 is in the middle + S32 center_sw_left = mRect.getWidth() / 2 + llfloor(mCurPanX); + S32 center_sw_bottom = mRect.getHeight() / 2 + llfloor(mCurPanY); + + glPushMatrix(); + + glTranslatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f); + + if( LLNetMap::sRotateMap ) + { + // rotate subsequent draws to agent rotation + rotation = atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ); + glRotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f); + } + + // figure out where agent is + S32 region_width = llround(gWorldPointer->getRegionWidthInMeters()); + + LLViewerRegion *regionp; + + for (regionp = gWorldPointer->mActiveRegionList.getFirstData(); + regionp; + regionp = gWorldPointer->mActiveRegionList.getNextData()) + { + // Find x and y position relative to camera's center. + LLVector3 origin_agent = regionp->getOriginAgent(); + LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent(); + F32 relative_x = (rel_region_pos.mV[0] / region_width) * gMiniMapScale; + F32 relative_y = (rel_region_pos.mV[1] / region_width) * gMiniMapScale; + + // background region rectangle + F32 bottom = relative_y; + F32 left = relative_x; + F32 top = bottom + gMiniMapScale ; + F32 right = left + gMiniMapScale ; + + if (regionp == gAgent.getRegion()) + { + glColor4f(1.f, 1.f, 1.f, 1.f); + } + else + { + glColor4f(0.8f, 0.8f, 0.8f, 1.f); + } + + if (!regionp->mAlive) + { + glColor4f(1.f, 0.5f, 0.5f, 1.f); + } + + + // Draw using texture. + LLViewerImage::bindTexture(regionp->getLand().getSTexture()); + glBegin(GL_QUADS); + glTexCoord2f(0.f, 1.f); + glVertex2f(left, top); + glTexCoord2f(0.f, 0.f); + glVertex2f(left, bottom); + glTexCoord2f(1.f, 0.f); + glVertex2f(right, bottom); + glTexCoord2f(1.f, 1.f); + glVertex2f(right, top); + glEnd(); + + // Draw water + glAlphaFunc(GL_GREATER, ABOVE_WATERLINE_ALPHA / 255.f ); + { + if (regionp->getLand().getWaterTexture()) + { + LLViewerImage::bindTexture(regionp->getLand().getWaterTexture()); + glBegin(GL_QUADS); + glTexCoord2f(0.f, 1.f); + glVertex2f(left, top); + glTexCoord2f(0.f, 0.f); + glVertex2f(left, bottom); + glTexCoord2f(1.f, 0.f); + glVertex2f(right, bottom); + glTexCoord2f(1.f, 1.f); + glVertex2f(right, top); + glEnd(); + } + } + glAlphaFunc(GL_GREATER,0.01f); + } + + + 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; + + if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f)) + { + mUpdateNow = FALSE; + mObjectImageCenterGlobal = new_center; + + // Center moved enough. + // Create the base texture. + U8 *default_texture = mObjectRawImagep->getData(); + memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() ); + + // Draw buildings + gObjectList.renderObjectsForMap(*this); + + mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight()); + + map_timer.reset(); + } + + LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal); + map_center_agent -= gAgent.getCameraPositionAgent(); + map_center_agent.mV[VX] *= gMiniMapScale/region_width; + map_center_agent.mV[VY] *= gMiniMapScale/region_width; + + LLViewerImage::bindTexture(mObjectImagep); + F32 image_half_width = 0.5f*mObjectMapPixels; + F32 image_half_height = 0.5f*mObjectMapPixels; + + glBegin(GL_QUADS); + glTexCoord2f(0.f, 1.f); + glVertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]); + glTexCoord2f(0.f, 0.f); + glVertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height); + glTexCoord2f(1.f, 0.f); + glVertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height); + glTexCoord2f(1.f, 1.f); + glVertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]); + glEnd(); + + glPopMatrix(); + + LLVector3d pos_global; + LLVector3 pos_map; + + // Draw avatars + for (regionp = gWorldPointer->mActiveRegionList.getFirstData(); + regionp; + regionp = gWorldPointer->mActiveRegionList.getNextData()) + { + const LLVector3d& origin_global = regionp->getOriginGlobal(); + + S32 count = regionp->mMapAvatars.count(); + S32 i; + LLVector3 pos_local; + U32 compact_local; + U8 bits; + for (i = 0; i < count; i++) + { + compact_local = regionp->mMapAvatars.get(i); + + bits = compact_local & 0xFF; + pos_local.mV[VZ] = F32(bits) * 4.f; + compact_local >>= 8; + + bits = compact_local & 0xFF; + pos_local.mV[VY] = (F32)bits; + compact_local >>= 8; + + bits = compact_local & 0xFF; + pos_local.mV[VX] = (F32)bits; + + pos_global.setVec( pos_local ); + pos_global += origin_global; + + pos_map = globalPosToView(pos_global); + LLWorldMapView::drawAvatar(pos_map.mV[VX], pos_map.mV[VY], + gAvatarMapColor, + pos_map.mV[VZ]); + } + } + + // Draw dot for autopilot target + if (gAgent.getAutoPilot()) + { + drawTracking( gAgent.getAutoPilotTargetGlobal(), gTrackColor ); + } + else + { + LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); + if ( LLTracker::TRACKING_AVATAR == tracking_status ) + { + drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor ); + } + else if ( LLTracker::TRACKING_LANDMARK == tracking_status + || LLTracker::TRACKING_LOCATION == tracking_status ) + { + drawTracking( LLTracker::getTrackedPositionGlobal(), gTrackColor ); + } + } + + // Draw dot for self avatar position + //drawTracking( gAgent.getPosGlobalFromAgent(gAgent.getFrameAgent().getCenter()), gSelfMapColor ); + pos_global = gAgent.getPositionGlobal(); + pos_map = globalPosToView(pos_global); + gl_draw_image(llround(pos_map.mV[VX]) - 4, + llround(pos_map.mV[VY]) - 4, + LLWorldMapView::sAvatarYouSmallImage, + LLColor4::white); + + // Draw frustum + F32 meters_to_pixels = gMiniMapScale/ gWorldPointer->getRegionWidthInMeters(); + + F32 horiz_fov = gCamera->getView() * gCamera->getAspect(); + F32 far_clip_meters = gCamera->getFar(); + F32 far_clip_pixels = far_clip_meters * meters_to_pixels; + + F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 ); + F32 half_width_pixels = half_width_meters * meters_to_pixels; + + F32 ctr_x = (F32)center_sw_left; + F32 ctr_y = (F32)center_sw_bottom; + + + LLGLSNoTexture no_texture; + + if( LLNetMap::sRotateMap ) + { + glColor4fv(gFrustumMapColor.mV); + + glBegin( GL_TRIANGLES ); + glVertex2f( ctr_x, ctr_y ); + glVertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels ); + glVertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels ); + glEnd(); + } + else + { + glColor4fv(gRotatingFrustumMapColor.mV); + + // If we don't rotate the map, we have to rotate the frustum. + glPushMatrix(); + glTranslatef( ctr_x, ctr_y, 0 ); + glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f); + glBegin( GL_TRIANGLES ); + glVertex2f( 0, 0 ); + glVertex2f( -half_width_pixels, far_clip_pixels ); + glVertex2f( half_width_pixels, far_clip_pixels ); + glEnd(); + glPopMatrix(); + } + } + + // Rotation of 0 means that North is up + setDirectionPos( mTextBoxEast, rotation ); + setDirectionPos( mTextBoxNorth, rotation + F_PI_BY_TWO ); + setDirectionPos( mTextBoxWest, rotation + F_PI ); + setDirectionPos( mTextBoxSouth, rotation + F_PI + F_PI_BY_TWO ); + + setDirectionPos( mTextBoxNorthEast, rotation + F_PI_BY_TWO / 2); + setDirectionPos( mTextBoxNorthWest, rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); + setDirectionPos( mTextBoxSouthWest, rotation + F_PI + F_PI_BY_TWO / 2); + setDirectionPos( mTextBoxSouthEast, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); + + LLUICtrl::draw(); +} + +LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos ) +{ + LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal(); + LLVector3 pos_local; + pos_local.setVec(relative_pos_global); // convert to floats from doubles + + pos_local.mV[VX] *= mPixelsPerMeter; + pos_local.mV[VY] *= mPixelsPerMeter; + // leave Z component in meters + + if( LLNetMap::sRotateMap ) + { + F32 radians = atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ); + LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); + pos_local.rotVec( rot ); + } + + pos_local.mV[VX] += mRect.getWidth() / 2 + mCurPanX; + pos_local.mV[VY] += mRect.getHeight() / 2 + mCurPanY; + + return pos_local; +} + +void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, + BOOL draw_arrow ) +{ + LLVector3 pos_local = globalPosToView( pos_global ); + if( (pos_local.mV[VX] < 0) || + (pos_local.mV[VY] < 0) || + (pos_local.mV[VX] >= mRect.getWidth()) || + (pos_local.mV[VY] >= mRect.getHeight()) ) + { + if (draw_arrow) + { + S32 x = llround( pos_local.mV[VX] ); + S32 y = llround( pos_local.mV[VY] ); + LLWorldMapView::drawTrackingCircle( mRect, x, y, color, 1, 10 ); + LLWorldMapView::drawTrackingArrow( mRect, x, y, color ); + } + } + else + { + LLWorldMapView::drawTrackingDot(pos_local.mV[VX], + pos_local.mV[VY], + color, + pos_local.mV[VZ]); + } +} + +LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y ) +{ + x -= llround(mRect.getWidth() / 2 + mCurPanX); + y -= llround(mRect.getHeight() / 2 + mCurPanY); + + LLVector3 pos_local( (F32)x, (F32)y, 0 ); + + F32 radians = - atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ); + + if( LLNetMap::sRotateMap ) + { + LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); + pos_local.rotVec( rot ); + } + + pos_local *= ( gWorldPointer->getRegionWidthInMeters() / gMiniMapScale ); + + LLVector3d pos_global; + pos_global.setVec( pos_local ); + pos_global += gAgent.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(gMiniMapScale - clicks*MAP_SCALE_INCREMENT, MAP_SCALE_MIN, MAP_SCALE_MAX)); + return TRUE; +} + +BOOL LLNetMap::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen ) +{ + BOOL handled = FALSE; + if (gDisconnected) + { + return FALSE; + } + if( getVisible() && pointInView( x, y ) ) + { + LLViewerRegion* region = gWorldPointer->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); + if( region ) + { + msg.assign( region->getName() ); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + char buffer[MAX_STRING]; + msg.append("\n"); + region->getHost().getHostName(buffer, MAX_STRING); + msg.append(buffer); + msg.append("\n"); + region->getHost().getString(buffer, MAX_STRING); + msg.append(buffer); +#endif + // FIXME: put in XML so it can be translated + msg.append("\n(Double-click to open Map)"); + + S32 SLOP = 4; + localPointToScreen( + x - SLOP, y - SLOP, + &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); + sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; + sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; + } + handled = TRUE; + } + return handled; +} + + +void LLNetMap::setDirectionPos( LLTextBox* text_box, F32 rotation ) +{ + // Rotation is in radians. + // Rotation of 0 means x = 1, y = 0 on the unit circle. + + + F32 map_half_height = (F32)(mRect.getHeight() / 2); + F32 map_half_width = (F32)(mRect.getWidth() / 2); + F32 text_half_height = (F32)(text_box->getRect().getHeight() / 2); + F32 text_half_width = (F32)(text_box->getRect().getWidth() / 2); + F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width ); + + // Inset by a little to account for position display. + radius -= 8.f; + + text_box->setOrigin( + llround(map_half_width - text_half_width + radius * cos( rotation )), + llround(map_half_height - text_half_height + radius * sin( rotation )) ); +} + +void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters ) +{ + LLVector3 local_pos; + local_pos.setVec( pos - mObjectImageCenterGlobal ); + + S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM); + renderPoint( local_pos, color, diameter_pixels ); +} + + +void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, + S32 diameter, S32 relative_height) +{ + if (diameter <= 0) + { + return; + } + + 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); + + if ((x_offset < 0) || (x_offset >= image_width)) + { + return; + } + if ((y_offset < 0) || (y_offset >= image_height)) + { + return; + } + + U8 *datap = mObjectRawImagep->getData(); + + S32 neg_radius = diameter / 2; + S32 pos_radius = diameter - neg_radius; + S32 x, y; + + if (relative_height > 0) + { + // ...point above agent + S32 px, py; + + // vertical line + px = x_offset; + for (y = -neg_radius; y < pos_radius; y++) + { + py = y_offset + y; + if ((py < 0) || (py >= image_height)) + { + continue; + } + S32 offset = px + py * image_width; + ((U32*)datap)[offset] = color.mAll; + } + + // top line + py = y_offset + pos_radius - 1; + for (x = -neg_radius; x < pos_radius; x++) + { + px = x_offset + x; + if ((px < 0) || (px >= image_width)) + { + continue; + } + S32 offset = px + py * image_width; + ((U32*)datap)[offset] = color.mAll; + } + } + else + { + // ...point level with agent + for (x = -neg_radius; x < pos_radius; x++) + { + S32 p_x = x_offset + x; + if ((p_x < 0) || (p_x >= image_width)) + { + continue; + } + + for (y = -neg_radius; y < pos_radius; y++) + { + S32 p_y = y_offset + y; + if ((p_y < 0) || (p_y >= image_height)) + { + continue; + } + S32 offset = p_x + p_y * image_width; + ((U32*)datap)[offset] = color.mAll; + } + } + } +} + +void LLNetMap::createObjectImage() +{ + // Find the size of the side of a square that surrounds the circle that surrounds mRect. + F32 half_width = (F32)(mRect.getWidth() / 2); + F32 half_height = (F32)(mRect.getHeight() / 2); + F32 radius = sqrt( half_width * half_width + half_height * half_height ); + S32 square_size = S32( 2 * radius ); + + // Find the least power of two >= the minimum size. + const S32 MIN_SIZE = 32; + const S32 MAX_SIZE = 256; + S32 img_size = MIN_SIZE; + while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) ) + { + img_size <<= 1; + } + + if( mObjectImagep.isNull() || + (mObjectImagep->getWidth() != img_size) || + (mObjectImagep->getHeight() != img_size) ) + { + mObjectRawImagep = new LLImageRaw(img_size, img_size, 4); + U8* data = mObjectRawImagep->getData(); + memset( data, 0, img_size * img_size * 4 ); + mObjectImagep = new LLImageGL( mObjectRawImagep, FALSE); + setScale(gMiniMapScale); + } + mUpdateNow = TRUE; +} + +BOOL LLNetMap::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + LLFloaterWorldMap::show(NULL, FALSE); + return TRUE; +} + +BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLMenuGL* menu = (LLMenuGL*)LLView::getViewByHandle(mPopupMenuHandle); + if (menu) + { + menu->buildDrawLabels(); + menu->updateParent(gMenuHolder); + LLMenuGL::showPopup(this, menu, x, y); + } + return TRUE; +} + + +// static +void LLNetMap::handleZoomLevel(void* which) +{ + intptr_t level = (intptr_t)which; + + switch(level) + { + case 0: + LLNetMap::sInstance->setScale(MAP_SCALE_MIN); + break; + case 1: + LLNetMap::sInstance->setScale(MAP_SCALE_MID); + break; + case 2: + LLNetMap::sInstance->setScale(MAP_SCALE_MAX); + break; + default: + break; + } +} + +bool LLRotateNetMapListener::handleEvent(LLPointer<LLEvent> event, const LLSD& user_data) +{ + LLNetMap::setRotateMap(event->getValue().asBoolean()); + return true; +} |