aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llnetmap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llnetmap.cpp')
-rw-r--r--linden/indra/newview/llnetmap.cpp826
1 files changed, 826 insertions, 0 deletions
diff --git a/linden/indra/newview/llnetmap.cpp b/linden/indra/newview/llnetmap.cpp
new file mode 100644
index 0000000..3db447a
--- /dev/null
+++ b/linden/indra/newview/llnetmap.cpp
@@ -0,0 +1,826 @@
1/**
2 * @file llnetmap.cpp
3 * @author James Cook
4 * @brief Display of surrounding regions, objects, and agents. View contained by LLFloaterMap.
5 *
6 * Copyright (c) 2001-2007, Linden Research, Inc.
7 *
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#include "llviewerprecompiledheaders.h"
30
31#include "llnetmap.h"
32
33#include "indra_constants.h"
34#include "llui.h"
35#include "linked_lists.h"
36#include "llmath.h" // clampf()
37#include "llfocusmgr.h"
38
39#include "llagent.h"
40#include "llcallingcard.h"
41#include "llcolorscheme.h"
42#include "llviewercontrol.h"
43#include "llfloaterworldmap.h"
44#include "llfloatermap.h"
45#include "llframetimer.h"
46#include "lltracker.h"
47#include "llmenugl.h"
48#include "llstatgraph.h"
49#include "llsurface.h"
50#include "lltextbox.h"
51#include "llviewercamera.h"
52#include "llviewerimage.h"
53#include "llviewerimagelist.h"
54#include "llviewermenu.h"
55#include "llviewerobjectlist.h"
56#include "llviewerparceloverlay.h"
57#include "llviewerregion.h"
58#include "llviewerwindow.h"
59#include "llvoavatar.h"
60#include "llworld.h"
61#include "llworldmapview.h" // shared draw code
62#include "viewer.h" // Only for constants!
63
64#include "llglheaders.h"
65
66const F32 MAP_SCALE_MIN = 64;
67const F32 MAP_SCALE_MID = 172;
68const F32 MAP_SCALE_MAX = 512;
69const F32 MAP_SCALE_INCREMENT = 16;
70
71const S32 TRACKING_RADIUS = 3;
72
73//static
74BOOL LLNetMap::sRotateMap = FALSE;
75LLNetMap* LLNetMap::sInstance = NULL;
76
77LLNetMap::LLNetMap(
78 const std::string& name,
79 const LLRect& rect,
80 const LLColor4& bg_color )
81 :
82 LLUICtrl(name, rect, FALSE, NULL, NULL), mBackgroundColor( bg_color ),
83 mObjectMapTPM(1.f),
84 mObjectMapPixels(255.f),
85 mTargetPanX( 0.f ),
86 mTargetPanY( 0.f ),
87 mCurPanX( 0.f ),
88 mCurPanY( 0.f ),
89 mUpdateNow( FALSE )
90{
91 mPixelsPerMeter = gMiniMapScale / REGION_WIDTH_METERS;
92
93 LLNetMap::sRotateMap = gSavedSettings.getBOOL( "MiniMapRotate" );
94
95 // Surface texture is dynamically generated/updated.
96// createObjectImage();
97
98 mObjectImageCenterGlobal = gAgent.getCameraPositionGlobal();
99
100 const S32 DIR_WIDTH = 10;
101 const S32 DIR_HEIGHT = 10;
102 LLRect major_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH, 0 );
103
104 mTextBoxNorth = new LLTextBox( "N", major_dir_rect );
105 mTextBoxNorth->setDropshadowVisible( TRUE );
106 addChild( mTextBoxNorth );
107
108 LLColor4 minor_color( 1.f, 1.f, 1.f, .7f );
109
110 mTextBoxEast = new LLTextBox( "E", major_dir_rect );
111 mTextBoxEast->setColor( minor_color );
112 addChild( mTextBoxEast );
113
114 mTextBoxWest = new LLTextBox( "W", major_dir_rect );
115 mTextBoxWest->setColor( minor_color );
116 addChild( mTextBoxWest );
117
118 mTextBoxSouth = new LLTextBox( "S", major_dir_rect );
119 mTextBoxSouth->setColor( minor_color );
120 addChild( mTextBoxSouth );
121
122 LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0 );
123
124 mTextBoxSouthEast = new LLTextBox( "SE", minor_dir_rect );
125 mTextBoxSouthEast->setColor( minor_color );
126 addChild( mTextBoxSouthEast );
127
128 mTextBoxNorthEast = new LLTextBox( "NE", minor_dir_rect );
129 mTextBoxNorthEast->setColor( minor_color );
130 addChild( mTextBoxNorthEast );
131
132 mTextBoxSouthWest = new LLTextBox( "SW", minor_dir_rect );
133 mTextBoxSouthWest->setColor( minor_color );
134 addChild( mTextBoxSouthWest );
135
136 mTextBoxNorthWest = new LLTextBox( "NW", minor_dir_rect );
137 mTextBoxNorthWest->setColor( minor_color );
138 addChild( mTextBoxNorthWest );
139
140 // Right-click menu
141 LLMenuGL* menu;
142 menu = new LLMenuGL("popup");
143 menu->setCanTearOff(FALSE);
144 menu->append(new LLMenuItemCallGL("Zoom Close", handleZoomLevel,
145 NULL, (void*)2) );
146 menu->append(new LLMenuItemCallGL("Zoom Medium", handleZoomLevel,
147 NULL, (void*)1) );
148 menu->append(new LLMenuItemCallGL("Zoom Far", handleZoomLevel,
149 NULL, (void*)0) );
150 menu->appendSeparator();
151 menu->append(new LLMenuItemCallGL("Stop Tracking", &LLTracker::stopTracking,
152 &LLTracker::isTracking, NULL) );
153 menu->setVisible(FALSE);
154 addChild(menu);
155 mPopupMenuHandle = menu->mViewHandle;
156
157 sInstance = this;
158
159 gSavedSettings.getControl("MiniMapRotate")->addListener(&mNetMapListener);
160}
161
162LLNetMap::~LLNetMap()
163{
164 sInstance = NULL;
165}
166
167EWidgetType LLNetMap::getWidgetType() const
168{
169 return WIDGET_TYPE_NET_MAP;
170}
171
172LLString LLNetMap::getWidgetTag() const
173{
174 return LL_NET_MAP_TAG;
175}
176
177
178void LLNetMap::setScale( F32 scale )
179{
180 gMiniMapScale = scale;
181 if (gMiniMapScale == 0.f)
182 {
183 gMiniMapScale = 0.1f;
184 }
185
186 if (mObjectImagep.notNull())
187 {
188 F32 half_width = (F32)(mRect.getWidth() / 2);
189 F32 half_height = (F32)(mRect.getHeight() / 2);
190 F32 radius = sqrt( half_width * half_width + half_height * half_height );
191
192 F32 region_widths = (2.f*radius)/gMiniMapScale;
193
194 F32 meters;
195 if (!gWorldPointer)
196 {
197 // Hack! Sometimes world hasn't been initialized at this point.
198 meters = 256.f*region_widths;
199 }
200 else
201 {
202 meters = region_widths * gWorldPointer->getRegionWidthInMeters();
203 }
204
205 F32 num_pixels = (F32)mObjectImagep->getWidth();
206 mObjectMapTPM = num_pixels/meters;
207 mObjectMapPixels = 2.f*radius;
208 }
209
210 mPixelsPerMeter = gMiniMapScale / REGION_WIDTH_METERS;
211
212 mUpdateNow = TRUE;
213}
214
215void LLNetMap::translatePan( F32 delta_x, F32 delta_y )
216{
217 mTargetPanX += delta_x;
218 mTargetPanY += delta_y;
219}
220
221
222///////////////////////////////////////////////////////////////////////////////////
223
224void LLNetMap::draw()
225{
226 static LLFrameTimer map_timer;
227
228 if (!getVisible() || !gWorldPointer)
229 {
230 return;
231 }
232 if (mObjectImagep.isNull())
233 {
234 createObjectImage();
235 }
236
237 mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
238 mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
239
240 // Prepare a scissor region
241 // GLint params[4];
242 // glGetIntegerv( GL_SCISSOR_BOX, params );
243 F32 rotation = 0;
244
245 {
246 LLGLEnable scissor(GL_SCISSOR_TEST);
247
248 {
249 LLGLSNoTexture no_texture;
250 LLUI::setScissorRegionLocal(LLRect(0, mRect.getHeight(), mRect.getWidth(), 0));
251
252 glMatrixMode(GL_MODELVIEW);
253
254 // Draw background rectangle
255 glColor4fv( mBackgroundColor.mV );
256 gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0);
257 }
258
259 // region 0,0 is in the middle
260 S32 center_sw_left = mRect.getWidth() / 2 + llfloor(mCurPanX);
261 S32 center_sw_bottom = mRect.getHeight() / 2 + llfloor(mCurPanY);
262
263 glPushMatrix();
264
265 glTranslatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f);
266
267 if( LLNetMap::sRotateMap )
268 {
269 // rotate subsequent draws to agent rotation
270 rotation = atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] );
271 glRotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f);
272 }
273
274 // figure out where agent is
275 S32 region_width = llround(gWorldPointer->getRegionWidthInMeters());
276
277 LLViewerRegion *regionp;
278
279 for (regionp = gWorldPointer->mActiveRegionList.getFirstData();
280 regionp;
281 regionp = gWorldPointer->mActiveRegionList.getNextData())
282 {
283 // Find x and y position relative to camera's center.
284 LLVector3 origin_agent = regionp->getOriginAgent();
285 LLVector3 rel_region_pos = origin_agent - gAgent.getCameraPositionAgent();
286 F32 relative_x = (rel_region_pos.mV[0] / region_width) * gMiniMapScale;
287 F32 relative_y = (rel_region_pos.mV[1] / region_width) * gMiniMapScale;
288
289 // background region rectangle
290 F32 bottom = relative_y;
291 F32 left = relative_x;
292 F32 top = bottom + gMiniMapScale ;
293 F32 right = left + gMiniMapScale ;
294
295 if (regionp == gAgent.getRegion())
296 {
297 glColor4f(1.f, 1.f, 1.f, 1.f);
298 }
299 else
300 {
301 glColor4f(0.8f, 0.8f, 0.8f, 1.f);
302 }
303
304 if (!regionp->mAlive)
305 {
306 glColor4f(1.f, 0.5f, 0.5f, 1.f);
307 }
308
309
310 // Draw using texture.
311 LLViewerImage::bindTexture(regionp->getLand().getSTexture());
312 glBegin(GL_QUADS);
313 glTexCoord2f(0.f, 1.f);
314 glVertex2f(left, top);
315 glTexCoord2f(0.f, 0.f);
316 glVertex2f(left, bottom);
317 glTexCoord2f(1.f, 0.f);
318 glVertex2f(right, bottom);
319 glTexCoord2f(1.f, 1.f);
320 glVertex2f(right, top);
321 glEnd();
322
323 // Draw water
324 glAlphaFunc(GL_GREATER, ABOVE_WATERLINE_ALPHA / 255.f );
325 {
326 if (regionp->getLand().getWaterTexture())
327 {
328 LLViewerImage::bindTexture(regionp->getLand().getWaterTexture());
329 glBegin(GL_QUADS);
330 glTexCoord2f(0.f, 1.f);
331 glVertex2f(left, top);
332 glTexCoord2f(0.f, 0.f);
333 glVertex2f(left, bottom);
334 glTexCoord2f(1.f, 0.f);
335 glVertex2f(right, bottom);
336 glTexCoord2f(1.f, 1.f);
337 glVertex2f(right, top);
338 glEnd();
339 }
340 }
341 glAlphaFunc(GL_GREATER,0.01f);
342 }
343
344
345 LLVector3d old_center = mObjectImageCenterGlobal;
346 LLVector3d new_center = gAgent.getCameraPositionGlobal();
347
348 new_center.mdV[0] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[0]);
349 new_center.mdV[1] = (5.f/mObjectMapTPM)*floor(0.2f*mObjectMapTPM*new_center.mdV[1]);
350 new_center.mdV[2] = 0.f;
351
352 if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f))
353 {
354 mUpdateNow = FALSE;
355 mObjectImageCenterGlobal = new_center;
356
357 // Center moved enough.
358 // Create the base texture.
359 U8 *default_texture = mObjectRawImagep->getData();
360 memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() );
361
362 // Draw buildings
363 gObjectList.renderObjectsForMap(*this);
364
365 mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight());
366
367 map_timer.reset();
368 }
369
370 LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal);
371 map_center_agent -= gAgent.getCameraPositionAgent();
372 map_center_agent.mV[VX] *= gMiniMapScale/region_width;
373 map_center_agent.mV[VY] *= gMiniMapScale/region_width;
374
375 LLViewerImage::bindTexture(mObjectImagep);
376 F32 image_half_width = 0.5f*mObjectMapPixels;
377 F32 image_half_height = 0.5f*mObjectMapPixels;
378
379 glBegin(GL_QUADS);
380 glTexCoord2f(0.f, 1.f);
381 glVertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]);
382 glTexCoord2f(0.f, 0.f);
383 glVertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height);
384 glTexCoord2f(1.f, 0.f);
385 glVertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height);
386 glTexCoord2f(1.f, 1.f);
387 glVertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
388 glEnd();
389
390 glPopMatrix();
391
392 LLVector3d pos_global;
393 LLVector3 pos_map;
394
395 // Draw avatars
396 for (regionp = gWorldPointer->mActiveRegionList.getFirstData();
397 regionp;
398 regionp = gWorldPointer->mActiveRegionList.getNextData())
399 {
400 const LLVector3d& origin_global = regionp->getOriginGlobal();
401
402 S32 count = regionp->mMapAvatars.count();
403 S32 i;
404 LLVector3 pos_local;
405 U32 compact_local;
406 U8 bits;
407 for (i = 0; i < count; i++)
408 {
409 compact_local = regionp->mMapAvatars.get(i);
410
411 bits = compact_local & 0xFF;
412 pos_local.mV[VZ] = F32(bits) * 4.f;
413 compact_local >>= 8;
414
415 bits = compact_local & 0xFF;
416 pos_local.mV[VY] = (F32)bits;
417 compact_local >>= 8;
418
419 bits = compact_local & 0xFF;
420 pos_local.mV[VX] = (F32)bits;
421
422 pos_global.setVec( pos_local );
423 pos_global += origin_global;
424
425 pos_map = globalPosToView(pos_global);
426 LLWorldMapView::drawAvatar(pos_map.mV[VX], pos_map.mV[VY],
427 gAvatarMapColor,
428 pos_map.mV[VZ]);
429 }
430 }
431
432 // Draw dot for autopilot target
433 if (gAgent.getAutoPilot())
434 {
435 drawTracking( gAgent.getAutoPilotTargetGlobal(), gTrackColor );
436 }
437 else
438 {
439 LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
440 if ( LLTracker::TRACKING_AVATAR == tracking_status )
441 {
442 drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor );
443 }
444 else if ( LLTracker::TRACKING_LANDMARK == tracking_status
445 || LLTracker::TRACKING_LOCATION == tracking_status )
446 {
447 drawTracking( LLTracker::getTrackedPositionGlobal(), gTrackColor );
448 }
449 }
450
451 // Draw dot for self avatar position
452 //drawTracking( gAgent.getPosGlobalFromAgent(gAgent.getFrameAgent().getCenter()), gSelfMapColor );
453 pos_global = gAgent.getPositionGlobal();
454 pos_map = globalPosToView(pos_global);
455 gl_draw_image(llround(pos_map.mV[VX]) - 4,
456 llround(pos_map.mV[VY]) - 4,
457 LLWorldMapView::sAvatarYouSmallImage,
458 LLColor4::white);
459
460 // Draw frustum
461 F32 meters_to_pixels = gMiniMapScale/ gWorldPointer->getRegionWidthInMeters();
462
463 F32 horiz_fov = gCamera->getView() * gCamera->getAspect();
464 F32 far_clip_meters = gCamera->getFar();
465 F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
466
467 F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
468 F32 half_width_pixels = half_width_meters * meters_to_pixels;
469
470 F32 ctr_x = (F32)center_sw_left;
471 F32 ctr_y = (F32)center_sw_bottom;
472
473
474 LLGLSNoTexture no_texture;
475
476 if( LLNetMap::sRotateMap )
477 {
478 glColor4fv(gFrustumMapColor.mV);
479
480 glBegin( GL_TRIANGLES );
481 glVertex2f( ctr_x, ctr_y );
482 glVertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
483 glVertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
484 glEnd();
485 }
486 else
487 {
488 glColor4fv(gRotatingFrustumMapColor.mV);
489
490 // If we don't rotate the map, we have to rotate the frustum.
491 glPushMatrix();
492 glTranslatef( ctr_x, ctr_y, 0 );
493 glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
494 glBegin( GL_TRIANGLES );
495 glVertex2f( 0, 0 );
496 glVertex2f( -half_width_pixels, far_clip_pixels );
497 glVertex2f( half_width_pixels, far_clip_pixels );
498 glEnd();
499 glPopMatrix();
500 }
501 }
502
503 // Rotation of 0 means that North is up
504 setDirectionPos( mTextBoxEast, rotation );
505 setDirectionPos( mTextBoxNorth, rotation + F_PI_BY_TWO );
506 setDirectionPos( mTextBoxWest, rotation + F_PI );
507 setDirectionPos( mTextBoxSouth, rotation + F_PI + F_PI_BY_TWO );
508
509 setDirectionPos( mTextBoxNorthEast, rotation + F_PI_BY_TWO / 2);
510 setDirectionPos( mTextBoxNorthWest, rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2);
511 setDirectionPos( mTextBoxSouthWest, rotation + F_PI + F_PI_BY_TWO / 2);
512 setDirectionPos( mTextBoxSouthEast, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2);
513
514 LLUICtrl::draw();
515}
516
517LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos )
518{
519 LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal();
520 LLVector3 pos_local;
521 pos_local.setVec(relative_pos_global); // convert to floats from doubles
522
523 pos_local.mV[VX] *= mPixelsPerMeter;
524 pos_local.mV[VY] *= mPixelsPerMeter;
525 // leave Z component in meters
526
527 if( LLNetMap::sRotateMap )
528 {
529 F32 radians = atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] );
530 LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f));
531 pos_local.rotVec( rot );
532 }
533
534 pos_local.mV[VX] += mRect.getWidth() / 2 + mCurPanX;
535 pos_local.mV[VY] += mRect.getHeight() / 2 + mCurPanY;
536
537 return pos_local;
538}
539
540void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color,
541 BOOL draw_arrow )
542{
543 LLVector3 pos_local = globalPosToView( pos_global );
544 if( (pos_local.mV[VX] < 0) ||
545 (pos_local.mV[VY] < 0) ||
546 (pos_local.mV[VX] >= mRect.getWidth()) ||
547 (pos_local.mV[VY] >= mRect.getHeight()) )
548 {
549 if (draw_arrow)
550 {
551 S32 x = llround( pos_local.mV[VX] );
552 S32 y = llround( pos_local.mV[VY] );
553 LLWorldMapView::drawTrackingCircle( mRect, x, y, color, 1, 10 );
554 LLWorldMapView::drawTrackingArrow( mRect, x, y, color );
555 }
556 }
557 else
558 {
559 LLWorldMapView::drawTrackingDot(pos_local.mV[VX],
560 pos_local.mV[VY],
561 color,
562 pos_local.mV[VZ]);
563 }
564}
565
566LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
567{
568 x -= llround(mRect.getWidth() / 2 + mCurPanX);
569 y -= llround(mRect.getHeight() / 2 + mCurPanY);
570
571 LLVector3 pos_local( (F32)x, (F32)y, 0 );
572
573 F32 radians = - atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] );
574
575 if( LLNetMap::sRotateMap )
576 {
577 LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f));
578 pos_local.rotVec( rot );
579 }
580
581 pos_local *= ( gWorldPointer->getRegionWidthInMeters() / gMiniMapScale );
582
583 LLVector3d pos_global;
584 pos_global.setVec( pos_local );
585 pos_global += gAgent.getCameraPositionGlobal();
586
587 return pos_global;
588}
589
590BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
591{
592 // note that clicks are reversed from what you'd think
593 setScale(llclamp(gMiniMapScale - clicks*MAP_SCALE_INCREMENT, MAP_SCALE_MIN, MAP_SCALE_MAX));
594 return TRUE;
595}
596
597BOOL LLNetMap::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen )
598{
599 BOOL handled = FALSE;
600 if (gDisconnected)
601 {
602 return FALSE;
603 }
604 if( getVisible() && pointInView( x, y ) )
605 {
606 LLViewerRegion* region = gWorldPointer->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
607 if( region )
608 {
609 msg.assign( region->getName() );
610
611#ifndef LL_RELEASE_FOR_DOWNLOAD
612 char buffer[MAX_STRING];
613 msg.append("\n");
614 region->getHost().getHostName(buffer, MAX_STRING);
615 msg.append(buffer);
616 msg.append("\n");
617 region->getHost().getString(buffer, MAX_STRING);
618 msg.append(buffer);
619#endif
620 // *TODO: put this under the control of XUI so it can be
621 // translated.
622 msg.append("\n(Double-click to open Map)");
623
624 S32 SLOP = 4;
625 localPointToScreen(
626 x - SLOP, y - SLOP,
627 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
628 sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
629 sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
630 }
631 handled = TRUE;
632 }
633 return handled;
634}
635
636
637void LLNetMap::setDirectionPos( LLTextBox* text_box, F32 rotation )
638{
639 // Rotation is in radians.
640 // Rotation of 0 means x = 1, y = 0 on the unit circle.
641
642
643 F32 map_half_height = (F32)(mRect.getHeight() / 2);
644 F32 map_half_width = (F32)(mRect.getWidth() / 2);
645 F32 text_half_height = (F32)(text_box->getRect().getHeight() / 2);
646 F32 text_half_width = (F32)(text_box->getRect().getWidth() / 2);
647 F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width );
648
649 // Inset by a little to account for position display.
650 radius -= 8.f;
651
652 text_box->setOrigin(
653 llround(map_half_width - text_half_width + radius * cos( rotation )),
654 llround(map_half_height - text_half_height + radius * sin( rotation )) );
655}
656
657void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters )
658{
659 LLVector3 local_pos;
660 local_pos.setVec( pos - mObjectImageCenterGlobal );
661
662 S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM);
663 renderPoint( local_pos, color, diameter_pixels );
664}
665
666
667void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color,
668 S32 diameter, S32 relative_height)
669{
670 if (diameter <= 0)
671 {
672 return;
673 }
674
675 const S32 image_width = (S32)mObjectImagep->getWidth();
676 const S32 image_height = (S32)mObjectImagep->getHeight();
677
678 S32 x_offset = llround(pos_local.mV[VX] * mObjectMapTPM + image_width / 2);
679 S32 y_offset = llround(pos_local.mV[VY] * mObjectMapTPM + image_height / 2);
680
681 if ((x_offset < 0) || (x_offset >= image_width))
682 {
683 return;
684 }
685 if ((y_offset < 0) || (y_offset >= image_height))
686 {
687 return;
688 }
689
690 U8 *datap = mObjectRawImagep->getData();
691
692 S32 neg_radius = diameter / 2;
693 S32 pos_radius = diameter - neg_radius;
694 S32 x, y;
695
696 if (relative_height > 0)
697 {
698 // ...point above agent
699 S32 px, py;
700
701 // vertical line
702 px = x_offset;
703 for (y = -neg_radius; y < pos_radius; y++)
704 {
705 py = y_offset + y;
706 if ((py < 0) || (py >= image_height))
707 {
708 continue;
709 }
710 S32 offset = px + py * image_width;
711 ((U32*)datap)[offset] = color.mAll;
712 }
713
714 // top line
715 py = y_offset + pos_radius - 1;
716 for (x = -neg_radius; x < pos_radius; x++)
717 {
718 px = x_offset + x;
719 if ((px < 0) || (px >= image_width))
720 {
721 continue;
722 }
723 S32 offset = px + py * image_width;
724 ((U32*)datap)[offset] = color.mAll;
725 }
726 }
727 else
728 {
729 // ...point level with agent
730 for (x = -neg_radius; x < pos_radius; x++)
731 {
732 S32 p_x = x_offset + x;
733 if ((p_x < 0) || (p_x >= image_width))
734 {
735 continue;
736 }
737
738 for (y = -neg_radius; y < pos_radius; y++)
739 {
740 S32 p_y = y_offset + y;
741 if ((p_y < 0) || (p_y >= image_height))
742 {
743 continue;
744 }
745 S32 offset = p_x + p_y * image_width;
746 ((U32*)datap)[offset] = color.mAll;
747 }
748 }
749 }
750}
751
752void LLNetMap::createObjectImage()
753{
754 // Find the size of the side of a square that surrounds the circle that surrounds mRect.
755 F32 half_width = (F32)(mRect.getWidth() / 2);
756 F32 half_height = (F32)(mRect.getHeight() / 2);
757 F32 radius = sqrt( half_width * half_width + half_height * half_height );
758 S32 square_size = S32( 2 * radius );
759
760 // Find the least power of two >= the minimum size.
761 const S32 MIN_SIZE = 32;
762 const S32 MAX_SIZE = 256;
763 S32 img_size = MIN_SIZE;
764 while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) )
765 {
766 img_size <<= 1;
767 }
768
769 if( mObjectImagep.isNull() ||
770 (mObjectImagep->getWidth() != img_size) ||
771 (mObjectImagep->getHeight() != img_size) )
772 {
773 mObjectRawImagep = new LLImageRaw(img_size, img_size, 4);
774 U8* data = mObjectRawImagep->getData();
775 memset( data, 0, img_size * img_size * 4 );
776 mObjectImagep = new LLImageGL( mObjectRawImagep, FALSE);
777 setScale(gMiniMapScale);
778 }
779 mUpdateNow = TRUE;
780}
781
782BOOL LLNetMap::handleDoubleClick( S32 x, S32 y, MASK mask )
783{
784 LLFloaterWorldMap::show(NULL, FALSE);
785 return TRUE;
786}
787
788BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
789{
790 LLMenuGL* menu = (LLMenuGL*)LLView::getViewByHandle(mPopupMenuHandle);
791 if (menu)
792 {
793 menu->buildDrawLabels();
794 menu->updateParent(gMenuHolder);
795 LLMenuGL::showPopup(this, menu, x, y);
796 }
797 return TRUE;
798}
799
800
801// static
802void LLNetMap::handleZoomLevel(void* which)
803{
804 intptr_t level = (intptr_t)which;
805
806 switch(level)
807 {
808 case 0:
809 LLNetMap::sInstance->setScale(MAP_SCALE_MIN);
810 break;
811 case 1:
812 LLNetMap::sInstance->setScale(MAP_SCALE_MID);
813 break;
814 case 2:
815 LLNetMap::sInstance->setScale(MAP_SCALE_MAX);
816 break;
817 default:
818 break;
819 }
820}
821
822bool LLRotateNetMapListener::handleEvent(LLPointer<LLEvent> event, const LLSD& user_data)
823{
824 LLNetMap::setRotateMap(event->getValue().asBoolean());
825 return true;
826}